aiobungie

A Pythonic async/await wrapper for interacting with the Bungie API.

Base client.

Example
import aiobungie

client = aiobungie.Client('YOUR_API_KEY')

# Search for Destiny2 users.
async def main() -> None:
    async with client.rest:
        users = await client.search_users('Crit')

        # Iterate over the users and take the first 5 results.
        for user in users.take(5):
            print(f'{user.name} ({user.code})')

            # Iterate through the users memberships.
            for membership in user.memberships:
                print(membership.type, membership.id)

client.run(main()) # or asyncio.run(main())

Single RESTClient instance.

The difference between base client and the REST clients:

  • No Hight-Level concepts.
  • All returned data are pure JSON objects from the API.
  • No object creation.
Example
import aiobungie

async def main() -> None:
    # Using `async with` context manager to close the session properly.
    async with aiobungie.RESTClient("TOKEN") as rest:
        payload = await rest.fetch_player('Fate怒', 4275)

        for membership in payload:
            print(membership['membershipId'], membership['iconPath'])

import asyncio
asyncio.run(main())

REST client pool.

A REST client pool allows you to acquire multiple RESTClient instances that shares the same connection.

Example
import aiobungie
import asyncio

pool = aiobungie.RESTPool("token")

async def func1() -> None:
    async with pool.acquire() as instance:
        tokens = await instance.fetch_oauth2_tokens('code')
        pool.metadata['tokens'] = tokens

# Other instance may access the tokens from pool since its shared.

async def func2() -> None:
    async with pool.acquire() as instance:
        tokens = pool.metadata['tokens']
        tokens = await instance.refresh_access_token(tokens.refresh_token)

async def main() -> None:
    await asyncio.gather(func1(), func2())

asyncio.run(main())

Should you use the base client or the REST client? This returns to you. For an example if you're building a website.

You can use python as a REST API in the backend with the RESTClient since all returned object are JSON objects. Which gives you the freedom to deserialize it and implement your own logic in the front-end.

Or of you're building a Discord bot for an example or something simple. The base client is the way to go.

  1# MIT License
  2#
  3# Copyright (c) 2020 - Present nxtlo
  4#
  5# Permission is hereby granted, free of charge, to any person obtaining a copy
  6# of this software and associated documentation files (the "Software"), to deal
  7# in the Software without restriction, including without limitation the rights
  8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9# copies of the Software, and to permit persons to whom the Software is
 10# furnished to do so, subject to the following conditions:
 11#
 12# The above copyright notice and this permission notice shall be included in all
 13# copies or substantial portions of the Software.
 14#
 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 21# SOFTWARE.
 22
 23"""A Pythonic `async`/`await` wrapper for interacting with the Bungie API.
 24
 25Base client.
 26
 27Example
 28-------
 29```py
 30import aiobungie
 31
 32client = aiobungie.Client('YOUR_API_KEY')
 33
 34# Search for Destiny2 users.
 35async def main() -> None:
 36    async with client.rest:
 37        users = await client.search_users('Crit')
 38
 39        # Iterate over the users and take the first 5 results.
 40        for user in users.take(5):
 41            print(f'{user.name} ({user.code})')
 42
 43            # Iterate through the users memberships.
 44            for membership in user.memberships:
 45                print(membership.type, membership.id)
 46
 47client.run(main()) # or asyncio.run(main())
 48```
 49
 50Single RESTClient instance.
 51
 52The difference between base client and the REST clients:
 53
 54* No Hight-Level concepts.
 55* All returned data are pure JSON objects from the API.
 56* No object creation.
 57
 58Example
 59-------
 60```py
 61import aiobungie
 62
 63async def main() -> None:
 64    # Using `async with` context manager to close the session properly.
 65    async with aiobungie.RESTClient("TOKEN") as rest:
 66        payload = await rest.fetch_player('Fate怒', 4275)
 67
 68        for membership in payload:
 69            print(membership['membershipId'], membership['iconPath'])
 70
 71import asyncio
 72asyncio.run(main())
 73```
 74
 75REST client pool.
 76
 77A REST client pool allows you to acquire multiple `RESTClient` instances that shares the same connection.
 78
 79Example
 80-------
 81```py
 82import aiobungie
 83import asyncio
 84
 85pool = aiobungie.RESTPool("token")
 86
 87async def func1() -> None:
 88    async with pool.acquire() as instance:
 89        tokens = await instance.fetch_oauth2_tokens('code')
 90        pool.metadata['tokens'] = tokens
 91
 92# Other instance may access the tokens from pool since its shared.
 93
 94async def func2() -> None:
 95    async with pool.acquire() as instance:
 96        tokens = pool.metadata['tokens']
 97        tokens = await instance.refresh_access_token(tokens.refresh_token)
 98
 99async def main() -> None:
100    await asyncio.gather(func1(), func2())
101
102asyncio.run(main())
103```
104
105Should you use the base client or the REST client?
106This returns to you. For an example if you're building a website.
107
108You can use python as a REST API in the backend with the RESTClient since all returned object are JSON objects.
109Which gives you the freedom to deserialize it and implement your own logic in the front-end.
110
111Or of you're building a Discord bot for an example or something simple. The base client is the way to go.
112"""
113
114
115from __future__ import annotations
116
117from aiobungie import builders
118from aiobungie import crates
119from aiobungie import interfaces
120from aiobungie import traits
121from aiobungie import typedefs
122from aiobungie import url
123from aiobungie.client import Client
124from aiobungie.error import *
125from aiobungie.internal import iterators
126from aiobungie.internal.assets import Image
127from aiobungie.internal.enums import *
128from aiobungie.internal.factory import Factory
129from aiobungie.internal.iterators import *
130from aiobungie.rest import *
131from aiobungie.undefined import UNDEFINED
132from aiobungie.undefined import UndefinedOr
133from aiobungie.undefined import UndefinedType
134
135from .metadata import __about__
136from .metadata import __author__
137from .metadata import __docs__
138from .metadata import __email__
139from .metadata import __license__
140from .metadata import __url__
141from .metadata import __version__
142
143# Alias for crate for backwards compatibility.
144crate = crates
145
146# Activity enums
147from .crates.activity import Difficulty
148
149# Components enums
150from .crates.components import ComponentFields
151from .crates.components import ComponentPrivacy
152
153# Entity enums
154from .crates.entity import GatingScope
155from .crates.entity import ObjectiveUIStyle
156from .crates.entity import ValueUIStyle
157
158# Fireteam enums.
159from .crates.fireteams import FireteamActivity
160from .crates.fireteams import FireteamDate
161from .crates.fireteams import FireteamLanguage
162from .crates.fireteams import FireteamPlatform
163
164# Records enums
165from .crates.records import RecordState
166
167__all__ = [mod for mod in dir() if not mod.startswith("_")]  # type: ignore
@attrs.define(auto_exc=True)
class AiobungieError(builtins.RuntimeError):
74@attrs.define(auto_exc=True)
75class AiobungieError(RuntimeError):
76    """Base class that all other exceptions inherit from."""

Base class that all other exceptions inherit from.

AiobungieError()
2def __init__(self, ):
3    BaseException.__init__(self, )

Method generated by attrs for class AiobungieError.

Inherited Members
builtins.BaseException
with_traceback
@typing.final
class AmmoType(builtins.int, aiobungie.Enum):
643@typing.final
644class AmmoType(int, Enum):
645    """AN enum for Detyiny 2 ammo types."""
646
647    NONE = 0
648    PRIMARY = 1
649    SPECIAL = 2
650    HEAVY = 3

AN enum for Detyiny 2 ammo types.

NONE = <AmmoType.NONE: 0>
PRIMARY = <AmmoType.PRIMARY: 1>
SPECIAL = <AmmoType.SPECIAL: 2>
HEAVY = <AmmoType.HEAVY: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class BadRequest(aiobungie.HTTPError):
164@attrs.define(auto_exc=True)
165class BadRequest(HTTPError):
166    """An exception raised when requesting a resource with the provided data is wrong."""
167
168    url: typing.Optional[typedefs.StrOrURL]
169    """The URL/endpoint caused this error."""
170
171    body: typing.Any
172    """The response body."""
173
174    headers: multidict.CIMultiDictProxy[str]
175    """The response headers."""
176
177    http_status: http.HTTPStatus = attrs.field(
178        default=http.HTTPStatus.BAD_REQUEST, init=False
179    )

An exception raised when requesting a resource with the provided data is wrong.

BadRequest( message: str, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str])
2def __init__(self, message, url, body, headers):
3    self.message = message
4    self.url = url
5    self.body = body
6    self.headers = headers
7    self.http_status = attr_dict['http_status'].default
8    BaseException.__init__(self, self.message,self.url,self.body,self.headers)

Method generated by attrs for class BadRequest.

url: Union[str, yarl.URL, NoneType]

The URL/endpoint caused this error.

body: Any

The response body.

headers: multidict._multidict.CIMultiDictProxy[str]

The response headers.

http_status: http.HTTPStatus

The response status.

Inherited Members
HTTPError
message
builtins.BaseException
with_traceback
@typing.final
class ClanMemberType(builtins.int, aiobungie.Enum):
698@typing.final
699class ClanMemberType(int, Enum):
700    """An enum for bungie clan member types."""
701
702    NONE = 0
703    BEGINNER = 1
704    MEMBER = 2
705    ADMIN = 3
706    ACTING_FOUNDER = 4
707    FOUNDER = 5

An enum for bungie clan member types.

NONE = <ClanMemberType.NONE: 0>
BEGINNER = <ClanMemberType.BEGINNER: 1>
MEMBER = <ClanMemberType.MEMBER: 2>
ADMIN = <ClanMemberType.ADMIN: 3>
ACTING_FOUNDER = <ClanMemberType.ACTING_FOUNDER: 4>
FOUNDER = <ClanMemberType.FOUNDER: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Class(builtins.int, aiobungie.Enum):
474@typing.final
475class Class(int, Enum):
476    """An Enum for Destiny character classes."""
477
478    TITAN = 0
479    HUNTER = 1
480    WARLOCK = 2
481    UNKNOWN = 3

An Enum for Destiny character classes.

TITAN = <Class.TITAN: 0>
HUNTER = <Class.HUNTER: 1>
WARLOCK = <Class.WARLOCK: 2>
UNKNOWN = <Class.UNKNOWN: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class Client(aiobungie.traits.ClientApp):
  60class Client(traits.ClientApp):
  61    """Standard Bungie API client application.
  62
  63    This client deserialize the REST JSON responses using `aiobungie.internal.factory.Factory`
  64    and returns `aiobungie.crates` Python object implementations of the responses.
  65
  66    A `aiobungie.RESTClient` REST client can also be used alone for low-level concepts.
  67
  68    Example
  69    -------
  70    ```py
  71    import aiobungie
  72
  73    client = aiobungie.Client('...')
  74
  75    async def main():
  76        async with client.rest:
  77            user = await client.fetch_current_user_memberships('...')
  78            print(user)
  79    ```
  80
  81    Parameters
  82    -----------
  83    token: `str`
  84        Your Bungie's API key or Token from the developer's portal.
  85
  86    Other Parameters
  87    ----------------
  88    max_retries : `int`
  89        The max retries number to retry if the request hit a `5xx` status code.
  90    client_secret : `str | None`
  91        An optional application client secret,
  92        This is only needed if you're fetching OAuth2 tokens with this client.
  93    client_id : `int | None`
  94        An optional application client id,
  95        This is only needed if you're fetching OAuth2 tokens with this client.
  96    """
  97
  98    __slots__ = ("_rest", "_factory")
  99
 100    def __init__(
 101        self,
 102        token: str,
 103        /,
 104        *,
 105        client_secret: typing.Optional[str] = None,
 106        client_id: typing.Optional[int] = None,
 107        max_retries: int = 4,
 108    ) -> None:
 109
 110        self._rest = rest_.RESTClient(
 111            token,
 112            client_secret=client_secret,
 113            client_id=client_id,
 114            max_retries=max_retries,
 115        )
 116
 117        self._factory = factory_.Factory(self)
 118
 119    @property
 120    def factory(self) -> factory_.Factory:
 121        return self._factory
 122
 123    @property
 124    def rest(self) -> interfaces.RESTInterface:
 125        return self._rest
 126
 127    @property
 128    def request(self) -> Client:
 129        return self
 130
 131    @property
 132    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
 133        return self._rest.metadata
 134
 135    def run(
 136        self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False
 137    ) -> None:
 138        loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop()
 139        try:
 140            if not loop.is_running():
 141                loop.set_debug(debug)
 142                loop.run_until_complete(future)
 143
 144        except Exception as exc:
 145            raise RuntimeError(f"Failed to run {future.__qualname__}") from exc
 146
 147        except KeyboardInterrupt:
 148            _LOG.warn("Unexpected Keyboard interrupt. Exiting.")
 149            return
 150
 151    # * User methods.
 152
 153    async def fetch_current_user_memberships(self, access_token: str, /) -> user.User:
 154        """Fetch and return a user object of the bungie net user associated with account.
 155
 156        .. warning::
 157            This method requires OAuth2 scope and a Bearer access token.
 158
 159        Parameters
 160        ----------
 161        access_token : `str`
 162            A valid Bearer access token for the authorization.
 163
 164        Returns
 165        -------
 166        `aiobungie.crates.user.User`
 167            A user object includes the Destiny memberships and Bungie.net user.
 168        """
 169        resp = await self.rest.fetch_current_user_memberships(access_token)
 170
 171        return self.factory.deserialize_user(resp)
 172
 173    async def fetch_bungie_user(self, id: int, /) -> user.BungieUser:
 174        """Fetch a Bungie user by their BungieNet id.
 175
 176        .. note::
 177            This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id`
 178            for other memberships.
 179
 180        Parameters
 181        ----------
 182        id: `int`
 183            The user id.
 184
 185        Returns
 186        -------
 187        `aiobungie.crates.user.BungieUser`
 188            A Bungie user.
 189
 190        Raises
 191        ------
 192        `aiobungie.error.NotFound`
 193            The user was not found.
 194        """
 195        payload = await self.rest.fetch_bungie_user(id)
 196
 197        return self.factory.deserialize_bungie_user(payload)
 198
 199    async def search_users(
 200        self, name: str, /
 201    ) -> iterators.Iterator[user.SearchableDestinyUser]:
 202        """Search for players and return all players that matches the same name.
 203
 204        Parameters
 205        ----------
 206        name : `buildins.str`
 207            The user name.
 208
 209        Returns
 210        -------
 211        `aiobungie.iterators.Iterator[aiobungie.crates.DestinyMembership]`
 212            A sequence of destiny memberships.
 213        """
 214        payload = await self.rest.search_users(name)
 215
 216        return iterators.Iterator(
 217            [
 218                self.factory.deserialize_searched_user(user)
 219                for user in payload["searchResults"]
 220            ]
 221        )
 222
 223    async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]:
 224        """Fetch all available user themes.
 225
 226        Returns
 227        -------
 228        `collections.Sequence[aiobungie.crates.user.UserThemes]`
 229            A sequence of user themes.
 230        """
 231        data = await self.rest.fetch_user_themes()
 232
 233        return self.factory.deserialize_user_themes(data)
 234
 235    async def fetch_hard_types(
 236        self,
 237        credential: int,
 238        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
 239        /,
 240    ) -> user.HardLinkedMembership:
 241        """Gets any hard linked membership given a credential.
 242        Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now.
 243        Cross Save aware.
 244
 245        Parameters
 246        ----------
 247        credential: `int`
 248            A valid SteamID64
 249        type: `aiobungie.CredentialType`
 250            The credential type. This must not be changed
 251            Since its only credential that works "currently"
 252
 253        Returns
 254        -------
 255        `aiobungie.crates.user.HardLinkedMembership`
 256            Information about the hard linked data.
 257        """
 258
 259        payload = await self.rest.fetch_hardlinked_credentials(credential, type)
 260
 261        return user.HardLinkedMembership(
 262            id=int(payload["membershipId"]),
 263            type=enums.MembershipType(payload["membershipType"]),
 264            cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]),
 265        )
 266
 267    async def fetch_membership_from_id(
 268        self,
 269        id: int,
 270        /,
 271        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 272    ) -> user.User:
 273        """Fetch Bungie user's memberships from their id.
 274
 275        Notes
 276        -----
 277        * This returns both BungieNet membership and a sequence of the player's DestinyMemberships
 278        Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
 279        see `aiobungie.crates.user.DestinyMembership` for more details.
 280        * If you only want the bungie user. Consider using `Client.fetch_user` method.
 281
 282        Parameters
 283        ----------
 284        id : `int`
 285            The user's id.
 286        type : `aiobungie.MembershipType`
 287            The user's membership type.
 288
 289        Returns
 290        -------
 291        `aiobungie.crates.User`
 292            A Bungie user with their membership types.
 293
 294        Raises
 295        ------
 296        aiobungie.NotFound
 297            The requested user was not found.
 298        """
 299        payload = await self.rest.fetch_membership_from_id(id, type)
 300
 301        return self.factory.deserialize_user(payload)
 302
 303    async def fetch_user_credentials(
 304        self, access_token: str, membership_id: int, /
 305    ) -> collections.Sequence[user.UserCredentials]:
 306        """Fetch an array of credential types attached to the requested account.
 307
 308        .. note::
 309            This method require OAuth2 Bearer access token.
 310
 311        Parameters
 312        ----------
 313        access_token : `str`
 314            The bearer access token associated with the bungie account.
 315        membership_id : `int`
 316            The id of the membership to return.
 317
 318        Returns
 319        -------
 320        `collections.Sequence[aiobungie.crates.UserCredentials]`
 321            A sequence of the attached user credentials.
 322
 323        Raises
 324        ------
 325        `aiobungie.Unauthorized`
 326            The access token was wrong or no access token passed.
 327        """
 328        resp = await self.rest.fetch_user_credentials(access_token, membership_id)
 329
 330        return self.factory.deserialize_user_credentials(resp)
 331
 332    # * Destiny 2.
 333
 334    async def fetch_profile(
 335        self,
 336        member_id: int,
 337        type: typedefs.IntAnd[enums.MembershipType],
 338        components: list[enums.ComponentType],
 339        auth: typing.Optional[str] = None,
 340    ) -> components.Component:
 341        """
 342        Fetch a bungie profile passing components to the request.
 343
 344        Parameters
 345        ----------
 346        member_id: `int`
 347            The member's id.
 348        type: `aiobungie.MembershipType`
 349            A valid membership type.
 350        components : `list[aiobungie.ComponentType]`
 351            List of profile components to collect and return.
 352
 353        Other Parameters
 354        ----------------
 355        auth : `typing.Optional[str]`
 356            A Bearer access_token to make the request with.
 357            This is optional and limited to components that only requires an Authorization token.
 358
 359        Returns
 360        --------
 361        `aiobungie.crates.Component`
 362            A Destiny 2 player profile with its components.
 363            Only passed components will be available if they exists. Otherwise they will be `None`
 364
 365        Raises
 366        ------
 367        `aiobungie.MembershipTypeError`
 368            The provided membership type was invalid.
 369        """
 370        data = await self.rest.fetch_profile(member_id, type, components, auth)
 371        return self.factory.deserialize_components(data)
 372
 373    async def fetch_linked_profiles(
 374        self,
 375        member_id: int,
 376        member_type: typedefs.IntAnd[enums.MembershipType],
 377        /,
 378        *,
 379        all: bool = False,
 380    ) -> profile.LinkedProfile:
 381        """Returns a summary information about all profiles linked to the requested member.
 382
 383        The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
 384
 385        .. note::
 386            It will only return linked accounts whose linkages you are allowed to view.
 387
 388        Parameters
 389        ----------
 390        member_id : `int`
 391            The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
 392        member_type : `aiobungie.MembershipType`
 393            The type for the membership whose linked Destiny account you want to return.
 394
 395        Other Parameters
 396        ----------------
 397        all : `bool`
 398            If provided and set to `True`, All memberships regardless
 399            of whether they're obscured by overrides will be returned,
 400
 401            If provided and set to `False`, Only available memberships will be returned.
 402            The default for this is `False`.
 403
 404        Returns
 405        -------
 406        `aiobungie.crates.profile.LinkedProfile`
 407            A linked profile object.
 408        """
 409        resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all)
 410
 411        return self.factory.deserialize_linked_profiles(resp)
 412
 413    async def fetch_player(
 414        self,
 415        name: str,
 416        code: int,
 417        /,
 418        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
 419    ) -> collections.Sequence[user.DestinyMembership]:
 420        """Fetch a Destiny 2 player's memberships.
 421
 422        Parameters
 423        -----------
 424        name: `str`
 425            The unique Bungie player name.
 426        code : `int`
 427            The unique Bungie display name code.
 428        type: `aiobungie.internal.enums.MembershipType`
 429            The player's membership type, e,g. XBOX, STEAM, PSN
 430
 431        Returns
 432        --------
 433        `collections.Sequence[aiobungie.crates.DestinyMembership]`
 434            A sequence of the found Destiny 2 player memberships.
 435            An empty sequence will be returned if no one found.
 436
 437        Raises
 438        ------
 439        `aiobungie.MembershipTypeError`
 440            The provided membership type was invalid.
 441        """
 442        resp = await self.rest.fetch_player(name, code, type)
 443
 444        return self.factory.deserialize_destiny_memberships(resp)
 445
 446    async def fetch_character(
 447        self,
 448        member_id: int,
 449        membership_type: typedefs.IntAnd[enums.MembershipType],
 450        character_id: int,
 451        components: list[enums.ComponentType],
 452        auth: typing.Optional[str] = None,
 453    ) -> components.CharacterComponent:
 454        """Fetch a Destiny 2 character.
 455
 456        Parameters
 457        ----------
 458        member_id: `int`
 459            A valid bungie member id.
 460        character_id: `int`
 461            The Destiny character id to retrieve.
 462        membership_type: `aiobungie.internal.enums.MembershipType`
 463            The member's membership type.
 464        components: `list[aiobungie.ComponentType]`
 465            Multiple arguments of character components to collect and return.
 466
 467        Other Parameters
 468        ----------------
 469        auth : `typing.Optional[str]`
 470            A Bearer access_token to make the request with.
 471            This is optional and limited to components that only requires an Authorization token.
 472
 473        Returns
 474        -------
 475        `aiobungie.crates.CharacterComponent`
 476            A Bungie character component.
 477
 478        `aiobungie.MembershipTypeError`
 479            The provided membership type was invalid.
 480        """
 481        resp = await self.rest.fetch_character(
 482            member_id, membership_type, character_id, components, auth
 483        )
 484
 485        return self.factory.deserialize_character_component(resp)
 486
 487    async def fetch_unique_weapon_history(
 488        self,
 489        membership_id: int,
 490        character_id: int,
 491        membership_type: typedefs.IntAnd[enums.MembershipType],
 492    ) -> collections.Sequence[activity.ExtendedWeaponValues]:
 493        """Fetch details about unique weapon usage for a character. Includes all exotics.
 494
 495        Parameters
 496        ----------
 497        membership_id : `int`
 498            The Destiny user membership id.
 499        character_id : `int`
 500            The character id to retrieve.
 501        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
 502            The Destiny user's membership type.
 503
 504        Returns
 505        -------
 506        `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]`
 507            A sequence of the weapon's extended values.
 508        """
 509        resp = await self._rest.fetch_unique_weapon_history(
 510            membership_id, character_id, membership_type
 511        )
 512
 513        return [
 514            self._factory.deserialize_extended_weapon_values(weapon)
 515            for weapon in resp["weapons"]
 516        ]
 517
 518    # * Destiny 2 Activities.
 519
 520    async def fetch_activities(
 521        self,
 522        member_id: int,
 523        character_id: int,
 524        mode: typedefs.IntAnd[enums.GameMode],
 525        *,
 526        membership_type: typedefs.IntAnd[
 527            enums.MembershipType
 528        ] = enums.MembershipType.ALL,
 529        page: int = 0,
 530        limit: int = 250,
 531    ) -> iterators.Iterator[activity.Activity]:
 532        """Fetch a Destiny 2 activity for the specified character id.
 533
 534        Parameters
 535        ----------
 536        member_id: `int`
 537            The user id that starts with `4611`.
 538        character_id: `int`
 539            The id of the character to retrieve the activities for.
 540        mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]`
 541            This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
 542
 543        Other Parameters
 544        ----------------
 545        membership_type: `aiobungie.internal.enums.MembershipType`
 546            The Member ship type, if nothing was passed than it will return all.
 547        page: int
 548            The page number. Default is `0`
 549        limit: int
 550            Limit the returned result. Default is `250`.
 551
 552        Returns
 553        -------
 554        `aiobungie.iterators.Iterator[aiobungie.crates.Activity]`
 555            An iterator of the player's activities.
 556
 557        Raises
 558        ------
 559        `aiobungie.MembershipTypeError`
 560            The provided membership type was invalid.
 561        """
 562        resp = await self.rest.fetch_activities(
 563            member_id,
 564            character_id,
 565            mode,
 566            membership_type=membership_type,
 567            page=page,
 568            limit=limit,
 569        )
 570
 571        return self.factory.deserialize_activities(resp)
 572
 573    async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity:
 574        """Fetch a post activity details.
 575
 576        Parameters
 577        ----------
 578        instance_id: `int`
 579            The activity instance id.
 580
 581        Returns
 582        -------
 583        `aiobungie.crates.PostActivity`
 584           A post activity object.
 585        """
 586        resp = await self.rest.fetch_post_activity(instance_id)
 587
 588        return self.factory.deserialize_post_activity(resp)
 589
 590    async def fetch_aggregated_activity_stats(
 591        self,
 592        character_id: int,
 593        membership_id: int,
 594        membership_type: typedefs.IntAnd[enums.MembershipType],
 595    ) -> iterators.Iterator[activity.AggregatedActivity]:
 596        """Fetch aggregated activity stats for a character.
 597
 598        Parameters
 599        ----------
 600        character_id: `int`
 601            The id of the character to retrieve the activities for.
 602        membership_id: `int`
 603            The id of the user that started with `4611`.
 604        membership_type: `aiobungie.internal.enums.MembershipType`
 605            The Member ship type.
 606
 607        Returns
 608        -------
 609        `aiobungie.iterators.Iterator[aiobungie.crates.AggregatedActivity]`
 610            An iterator of the player's activities.
 611
 612        Raises
 613        ------
 614        `aiobungie.MembershipTypeError`
 615            The provided membership type was invalid.
 616        """
 617        resp = await self.rest.fetch_aggregated_activity_stats(
 618            character_id, membership_id, membership_type
 619        )
 620
 621        return self.factory.deserialize_aggregated_activities(resp)
 622
 623    # * Destiny 2 Clans or GroupsV2.
 624
 625    async def fetch_clan_from_id(
 626        self,
 627        id: int,
 628        /,
 629        access_token: typing.Optional[str] = None,
 630    ) -> clans.Clan:
 631        """Fetch a Bungie Clan by its id.
 632
 633        Parameters
 634        -----------
 635        id: `int`
 636            The clan id.
 637
 638        Returns
 639        --------
 640        `aiobungie.crates.Clan`
 641            An Bungie clan.
 642
 643        Raises
 644        ------
 645        `aiobungie.NotFound`
 646            The clan was not found.
 647        """
 648        resp = await self.rest.fetch_clan_from_id(id, access_token)
 649
 650        return self.factory.deserialize_clan(resp)
 651
 652    async def fetch_clan(
 653        self,
 654        name: str,
 655        /,
 656        access_token: typing.Optional[str] = None,
 657        *,
 658        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 659    ) -> clans.Clan:
 660        """Fetch a Clan by its name.
 661        This method will return the first clan found with given name.
 662
 663        Parameters
 664        ----------
 665        name: `str`
 666            The clan name
 667
 668        Other Parameters
 669        ----------------
 670        access_token : `typing.Optional[str]`
 671            An optional access token to make the request with.
 672
 673            If the token was bound to a member of the clan,
 674            This field `aiobungie.crates.Clan.current_user_membership` will be available
 675            and will return the membership of the user who made this request.
 676        type : `aiobungie.GroupType`
 677            The group type, Default is aiobungie.GroupType.CLAN.
 678
 679        Returns
 680        -------
 681        `aiobungie.crates.Clan`
 682            A Bungie clan.
 683
 684        Raises
 685        ------
 686        `aiobungie.NotFound`
 687            The clan was not found.
 688        """
 689        resp = await self.rest.fetch_clan(name, access_token, type=type)
 690
 691        return self.factory.deserialize_clan(resp)
 692
 693    async def fetch_clan_conversations(
 694        self, clan_id: int, /
 695    ) -> collections.Sequence[clans.ClanConversation]:
 696        """Fetch the conversations/chat channels of the given clan id.
 697
 698        Parameters
 699        ----------
 700        clan_id : `int`
 701            The clan id.
 702
 703        Returns
 704        `collections.Sequence[aiobungie.crates.ClanConversation]`
 705            A sequence of the clan chat channels.
 706        """
 707        resp = await self.rest.fetch_clan_conversations(clan_id)
 708
 709        return self.factory.deserialize_clan_conversations(resp)
 710
 711    async def fetch_clan_admins(
 712        self, clan_id: int, /
 713    ) -> iterators.Iterator[clans.ClanMember]:
 714        """Fetch the clan founder and admins.
 715
 716        Parameters
 717        ----------
 718        clan_id : `int`
 719            The clan id.
 720
 721        Returns
 722        -------
 723        `aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]`
 724            An iterator over the found clan admins and founder.
 725
 726        Raises
 727        ------
 728        `aiobungie.NotFound`
 729            The requested clan was not found.
 730        """
 731        resp = await self.rest.fetch_clan_admins(clan_id)
 732
 733        return self.factory.deserialize_clan_members(resp)
 734
 735    async def fetch_groups_for_member(
 736        self,
 737        member_id: int,
 738        member_type: typedefs.IntAnd[enums.MembershipType],
 739        /,
 740        *,
 741        filter: int = 0,
 742        group_type: enums.GroupType = enums.GroupType.CLAN,
 743    ) -> collections.Sequence[clans.GroupMember]:
 744        """Fetch information about the groups that a given member has joined.
 745
 746        Parameters
 747        ----------
 748        member_id : `int`
 749            The member's id
 750        member_type : `aiobungie.MembershipType`
 751            The member's membership type.
 752
 753        Other Parameters
 754        ----------------
 755        filter : `int`
 756            Filter apply to list of joined groups. This Default to `0`
 757        group_type : `aiobungie.GroupType`
 758            The group's type.
 759            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
 760
 761        Returns
 762        -------
 763        `collections.Sequence[aiobungie.crates.GroupMember]`
 764            A sequence of joined groups for the fetched member.
 765        """
 766        resp = await self.rest.fetch_groups_for_member(
 767            member_id, member_type, filter=filter, group_type=group_type
 768        )
 769
 770        return [
 771            self.factory.deserialize_group_member(group) for group in resp["results"]
 772        ]
 773
 774    async def fetch_potential_groups_for_member(
 775        self,
 776        member_id: int,
 777        member_type: typedefs.IntAnd[enums.MembershipType],
 778        /,
 779        *,
 780        filter: int = 0,
 781        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 782    ) -> collections.Sequence[clans.GroupMember]:
 783        """Fetch the potential groups for a clan member.
 784
 785        Parameters
 786        ----------
 787        member_id : `int`
 788            The member's id
 789        member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
 790            The member's membership type.
 791
 792        Other Parameters
 793        ----------------
 794        filter : `int`
 795            Filter apply to list of joined groups. This Default to `0`
 796        group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]`
 797            The group's type.
 798            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
 799
 800        Returns
 801        -------
 802        `collections.Sequence[aiobungie.crates.GroupMember]`
 803            A sequence of joined potential groups for the fetched member.
 804        """
 805        resp = await self.rest.fetch_potential_groups_for_member(
 806            member_id, member_type, filter=filter, group_type=group_type
 807        )
 808
 809        return [
 810            self.factory.deserialize_group_member(group) for group in resp["results"]
 811        ]
 812
 813    async def fetch_clan_members(
 814        self,
 815        clan_id: int,
 816        /,
 817        *,
 818        name: typing.Optional[str] = None,
 819        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 820    ) -> iterators.Iterator[clans.ClanMember]:
 821        """Fetch Bungie clan members.
 822
 823        Parameters
 824        ----------
 825        clan_id : `int`
 826            The clans id
 827
 828        Other Parameters
 829        ----------------
 830        name : `typing.Optional[str]`
 831            If provided, Only players matching this name will be returned.
 832        type : `aiobungie.MembershipType`
 833            An optional clan member's membership type.
 834            This parameter is used to filter the returned results
 835            by the provided membership, For an example XBox memberships only,
 836            Otherwise will return all memberships.
 837
 838        Returns
 839        -------
 840        `aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]`
 841            An iterator over the bungie clan members.
 842
 843        Raises
 844        ------
 845        `aiobungie.NotFound`
 846            The clan was not found.
 847        """
 848        resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name)
 849
 850        return self.factory.deserialize_clan_members(resp)
 851
 852    async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]:
 853        """Fetch the clan banners.
 854
 855        Returns
 856        -------
 857        `collections.Sequence[aiobungie.crates.ClanBanner]`
 858            A sequence of the clan banners.
 859        """
 860        resp = await self.rest.fetch_clan_banners()
 861
 862        return self.factory.deserialize_clan_banners(resp)
 863
 864    # This method is required to be here since it deserialize the clan.
 865    async def kick_clan_member(
 866        self,
 867        access_token: str,
 868        /,
 869        group_id: int,
 870        membership_id: int,
 871        membership_type: typedefs.IntAnd[enums.MembershipType],
 872    ) -> clans.Clan:
 873        """Kick a member from the clan.
 874
 875        .. note::
 876            This request requires OAuth2: oauth2: `AdminGroups` scope.
 877
 878        Parameters
 879        ----------
 880        access_token : `str`
 881            The bearer access token associated with the bungie account.
 882        group_id: `int`
 883            The group id.
 884        membership_id : `int`
 885            The member id to kick.
 886        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
 887            The member's membership type.
 888
 889        Returns
 890        -------
 891        `aiobungie.crates.clan.Clan`
 892            The clan that the member was kicked from.
 893        """
 894        resp = await self.rest.kick_clan_member(
 895            access_token,
 896            group_id=group_id,
 897            membership_id=membership_id,
 898            membership_type=membership_type,
 899        )
 900
 901        return self.factory.deserialize_clan(resp)
 902
 903    async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone:
 904        """Fetch a Bungie clan's weekly reward state.
 905
 906        Parameters
 907        ----------
 908        clan_id : `int`
 909            The clan's id.
 910
 911        Returns
 912        -------
 913        `aiobungie.crates.Milestone`
 914            A runtime status of the clan's milestone data.
 915        """
 916
 917        resp = await self.rest.fetch_clan_weekly_rewards(clan_id)
 918
 919        return self.factory.deserialize_milestone(resp)
 920
 921    # * Destiny 2 Entities aka Definitions.
 922
 923    async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity:
 924        """Fetch a static inventory item entity given a its hash.
 925
 926        Parameters
 927        ----------
 928        hash: `int`
 929            Inventory item's hash.
 930
 931        Returns
 932        -------
 933        `aiobungie.crates.InventoryEntity`
 934            A bungie inventory item.
 935        """
 936        resp = await self.rest.fetch_inventory_item(hash)
 937
 938        return self.factory.deserialize_inventory_entity(resp)
 939
 940    async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity:
 941        """Fetch a Destiny objective entity given a its hash.
 942
 943        Parameters
 944        ----------
 945        hash: `int`
 946            objective's hash.
 947
 948        Returns
 949        -------
 950        `aiobungie.crates.ObjectiveEntity`
 951            An objective entity item.
 952        """
 953        resp = await self.rest.fetch_objective_entity(hash)
 954
 955        return self.factory.deserialize_objective_entity(resp)
 956
 957    async def search_entities(
 958        self, name: str, entity_type: str, *, page: int = 0
 959    ) -> iterators.Iterator[entity.SearchableEntity]:
 960        """Search for Destiny2 entities given a name and its type.
 961
 962        Parameters
 963        ----------
 964        name : `str`
 965            The name of the entity, i.e., Thunderlord, One thousand voices.
 966        entity_type : `str`
 967            The type of the entity, AKA Definition,
 968            For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items.
 969
 970        Other Parameters
 971        ----------------
 972        page : `int`
 973            An optional page to return. Default to 0.
 974
 975        Returns
 976        -------
 977        `aiobungie.iterators.Iterator[aiobungie.crates.SearchableEntity]`
 978            An iterator over the found results matching the provided name.
 979        """
 980        resp = await self.rest.search_entities(name, entity_type, page=page)
 981
 982        return self.factory.deserialize_inventory_results(resp)
 983
 984    # Fireteams
 985
 986    async def fetch_fireteams(
 987        self,
 988        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
 989        *,
 990        platform: typedefs.IntAnd[
 991            fireteams.FireteamPlatform
 992        ] = fireteams.FireteamPlatform.ANY,
 993        language: typing.Union[
 994            fireteams.FireteamLanguage, str
 995        ] = fireteams.FireteamLanguage.ALL,
 996        date_range: int = 0,
 997        page: int = 0,
 998        slots_filter: int = 0,
 999    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
1000        """Fetch public Bungie fireteams with open slots.
1001
1002        Parameters
1003        ----------
1004        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1005            The fireteam activity type.
1006
1007        Other Parameters
1008        ----------------
1009        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1010            If this is provided. Then the results will be filtered with the given platform.
1011            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1012        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1013            A locale language to filter the used language in that fireteam.
1014            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1015        date_range : `int`
1016            An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`.
1017        page : `int`
1018            The page number. By default its `0` which returns all available activities.
1019        slots_filter : `int`
1020            Filter the returned fireteams based on available slots. Default is `0`
1021
1022        Returns
1023        -------
1024        `typing.Optional[collections.Sequence[fireteams.Fireteam]]`
1025            A sequence of `aiobungie.crates.Fireteam` or `None`.
1026        """
1027
1028        resp = await self.rest.fetch_fireteams(
1029            activity_type,
1030            platform=platform,
1031            language=language,
1032            date_range=date_range,
1033            page=page,
1034            slots_filter=slots_filter,
1035        )
1036
1037        return self.factory.deserialize_fireteams(resp)
1038
1039    async def fetch_avaliable_clan_fireteams(
1040        self,
1041        access_token: str,
1042        group_id: int,
1043        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1044        *,
1045        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1046        language: typing.Union[fireteams.FireteamLanguage, str],
1047        date_range: int = 0,
1048        page: int = 0,
1049        public_only: bool = False,
1050        slots_filter: int = 0,
1051    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
1052        """Fetch a clan's fireteams with open slots.
1053
1054        .. note::
1055            This method requires OAuth2: ReadGroups scope.
1056
1057        Parameters
1058        ----------
1059        access_token : `str`
1060            The bearer access token associated with the bungie account.
1061        group_id : `int`
1062            The group/clan id of the fireteam.
1063        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1064            The fireteam activity type.
1065
1066        Other Parameters
1067        ----------------
1068        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1069            If this is provided. Then the results will be filtered with the given platform.
1070            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1071        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1072            A locale language to filter the used language in that fireteam.
1073            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1074        date_range : `int`
1075            An integer to filter the date range of the returned fireteams. Defaults to `0`.
1076        page : `int`
1077            The page number. By default its `0` which returns all available activities.
1078        public_only: `bool`
1079            If set to True, Then only public fireteams will be returned.
1080        slots_filter : `int`
1081            Filter the returned fireteams based on available slots. Default is `0`
1082
1083        Returns
1084        -------
1085        `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]`
1086            A sequence of  fireteams found in the clan.
1087            `None` will be returned if nothing was found.
1088        """
1089        resp = await self.rest.fetch_avaliable_clan_fireteams(
1090            access_token,
1091            group_id,
1092            activity_type,
1093            platform=platform,
1094            language=language,
1095            date_range=date_range,
1096            page=page,
1097            public_only=public_only,
1098            slots_filter=slots_filter,
1099        )
1100
1101        return self.factory.deserialize_fireteams(resp)
1102
1103    async def fetch_clan_fireteam(
1104        self, access_token: str, fireteam_id: int, group_id: int
1105    ) -> fireteams.AvailableFireteam:
1106        """Fetch a specific clan fireteam.
1107
1108        .. note::
1109            This method requires OAuth2: ReadGroups scope.
1110
1111        Parameters
1112        ----------
1113        access_token : `str`
1114            The bearer access token associated with the bungie account.
1115        group_id : `int`
1116            The group/clan id to fetch the fireteam from.
1117        fireteam_id : `int`
1118            The fireteam id to fetch.
1119
1120        Returns
1121        -------
1122        `typing.Optional[aiobungie.crates.AvailableFireteam]`
1123            A sequence of available fireteams objects if exists. else `None` will be returned.
1124        """
1125        resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id)
1126
1127        return self.factory.deserialize_available_fireteams(
1128            resp, no_results=True
1129        )  # type: ignore[return-value]
1130
1131    async def fetch_my_clan_fireteams(
1132        self,
1133        access_token: str,
1134        group_id: int,
1135        *,
1136        include_closed: bool = True,
1137        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1138        language: typing.Union[fireteams.FireteamLanguage, str],
1139        filtered: bool = True,
1140        page: int = 0,
1141    ) -> collections.Sequence[fireteams.AvailableFireteam]:
1142        """A method that's similar to `fetch_fireteams` but requires OAuth2.
1143
1144        .. note::
1145            This method requires OAuth2: ReadGroups scope.
1146
1147        Parameters
1148        ----------
1149        access_token : str
1150            The bearer access token associated with the bungie account.
1151        group_id : int
1152            The group/clan id to fetch.
1153
1154        Other Parameters
1155        ----------------
1156        include_closed : bool
1157            If provided and set to True, It will also return closed fireteams.
1158            If provided and set to False, It will only return public fireteams. Default is True.
1159        platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]
1160            If this is provided. Then the results will be filtered with the given platform.
1161            Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
1162        language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]
1163            A locale language to filter the used language in that fireteam.
1164            Defaults to aiobungie.crates.FireteamLanguage.ALL
1165        filtered : bool
1166            If set to True, it will filter by clan. Otherwise not. Default is True.
1167        page : int
1168            The page number. By default its 0 which returns all available activities.
1169
1170        Returns
1171        -------
1172        `collections.Sequence[aiobungie.crates.AvailableFireteam]`
1173            A sequence of available fireteams objects if exists. else `None` will be returned.
1174        """
1175        resp = await self.rest.fetch_my_clan_fireteams(
1176            access_token,
1177            group_id,
1178            include_closed=include_closed,
1179            platform=platform,
1180            language=language,
1181            filtered=filtered,
1182            page=page,
1183        )
1184
1185        return self.factory.deserialize_available_fireteams(resp)  # type: ignore[return-value]
1186
1187    # Friends and social.
1188
1189    async def fetch_friends(
1190        self, access_token: str, /
1191    ) -> collections.Sequence[friends.Friend]:
1192        """Fetch bungie friend list.
1193
1194        .. note::
1195            This requests OAuth2: ReadUserData scope.
1196
1197        Parameters
1198        -----------
1199        access_token : `str`
1200            The bearer access token associated with the bungie account.
1201
1202        Returns
1203        -------
1204        `collections.Sequence[aiobungie.crates.Friend]`
1205            A sequence of the friends associated with that access token.
1206        """
1207
1208        resp = await self.rest.fetch_friends(access_token)
1209
1210        return self.factory.deserialize_friends(resp)
1211
1212    async def fetch_friend_requests(
1213        self, access_token: str, /
1214    ) -> friends.FriendRequestView:
1215        """Fetch pending bungie friend requests queue.
1216
1217        .. note::
1218            This requests OAuth2: ReadUserData scope.
1219
1220        Parameters
1221        -----------
1222        access_token : `str`
1223            The bearer access token associated with the bungie account.
1224
1225        Returns
1226        -------
1227        `aiobungie.crates.FriendRequestView`
1228            A friend requests view of that associated access token.
1229        """
1230
1231        resp = await self.rest.fetch_friend_requests(access_token)
1232
1233        return self.factory.deserialize_friend_requests(resp)
1234
1235    # Applications and Developer portal.
1236
1237    async def fetch_application(self, appid: int, /) -> application.Application:
1238        """Fetch a Bungie application.
1239
1240        Parameters
1241        -----------
1242        appid: `int`
1243            The application id.
1244
1245        Returns
1246        --------
1247        `aiobungie.crates.Application`
1248            A Bungie application.
1249        """
1250        resp = await self.rest.fetch_application(appid)
1251
1252        return self.factory.deserialize_app(resp)
1253
1254    # Milestones
1255
1256    async def fetch_public_milestone_content(
1257        self, milestone_hash: int, /
1258    ) -> milestones.MilestoneContent:
1259        """Fetch the milestone content given its hash.
1260
1261        Parameters
1262        ----------
1263        milestone_hash : `int`
1264            The milestone hash.
1265
1266        Returns
1267        -------
1268        `aiobungie.crates.milestones.MilestoneContent`
1269            A milestone content object.
1270        """
1271        resp = await self.rest.fetch_public_milestone_content(milestone_hash)
1272
1273        return self.factory.deserialize_public_milestone_content(resp)

Standard Bungie API client application.

This client deserialize the REST JSON responses using aiobungie.Factory and returns aiobungie.crates Python object implementations of the responses.

A aiobungie.RESTClient REST client can also be used alone for low-level concepts.

Example
import aiobungie

client = aiobungie.Client('...')

async def main():
    async with client.rest:
        user = await client.fetch_current_user_memberships('...')
        print(user)
Parameters
  • token (str): Your Bungie's API key or Token from the developer's portal.
Other Parameters
  • max_retries (int): The max retries number to retry if the request hit a 5xx status code.
  • client_secret (str | None): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client.
  • client_id (int | None): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
Client( token: str, /, *, client_secret: Optional[str] = None, client_id: Optional[int] = None, max_retries: int = 4)
100    def __init__(
101        self,
102        token: str,
103        /,
104        *,
105        client_secret: typing.Optional[str] = None,
106        client_id: typing.Optional[int] = None,
107        max_retries: int = 4,
108    ) -> None:
109
110        self._rest = rest_.RESTClient(
111            token,
112            client_secret=client_secret,
113            client_id=client_id,
114            max_retries=max_retries,
115        )
116
117        self._factory = factory_.Factory(self)

Returns the marshalling factory for the client.

rest: aiobungie.interfaces.rest.RESTInterface

Returns the REST client for the this client.

request: aiobungie.Client

A readonly ClientApp instance used for external requests.

metadata: collections.abc.MutableMapping[typing.Any, typing.Any]

A mutable mapping storage for the user's needs.

def run( self, future: collections.abc.Coroutine[typing.Any, None, None], debug: bool = False) -> None:
135    def run(
136        self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False
137    ) -> None:
138        loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop()
139        try:
140            if not loop.is_running():
141                loop.set_debug(debug)
142                loop.run_until_complete(future)
143
144        except Exception as exc:
145            raise RuntimeError(f"Failed to run {future.__qualname__}") from exc
146
147        except KeyboardInterrupt:
148            _LOG.warn("Unexpected Keyboard interrupt. Exiting.")
149            return

Runs a coroutine function until its complete.

This is equivalent to asyncio.get_event_loop().run_until_complete(...)

Parameters
  • future (collections.Coroutine[None, None, None]): A coroutine object.
  • debug (bool): Either to enable asyncio debug or not. Disabled by default.
Example
async def main() -> None:
    await fetch(...)

# Run the coroutine.
client.run(main())
async def fetch_current_user_memberships(self, access_token: str, /) -> aiobungie.crates.user.User:
153    async def fetch_current_user_memberships(self, access_token: str, /) -> user.User:
154        """Fetch and return a user object of the bungie net user associated with account.
155
156        .. warning::
157            This method requires OAuth2 scope and a Bearer access token.
158
159        Parameters
160        ----------
161        access_token : `str`
162            A valid Bearer access token for the authorization.
163
164        Returns
165        -------
166        `aiobungie.crates.user.User`
167            A user object includes the Destiny memberships and Bungie.net user.
168        """
169        resp = await self.rest.fetch_current_user_memberships(access_token)
170
171        return self.factory.deserialize_user(resp)

Fetch and return a user object of the bungie net user associated with account.

This method requires OAuth2 scope and a Bearer access token.

Parameters
  • access_token (str): A valid Bearer access token for the authorization.
Returns
  • aiobungie.crates.user.User: A user object includes the Destiny memberships and Bungie.net user.
async def fetch_bungie_user(self, id: int, /) -> aiobungie.crates.user.BungieUser:
173    async def fetch_bungie_user(self, id: int, /) -> user.BungieUser:
174        """Fetch a Bungie user by their BungieNet id.
175
176        .. note::
177            This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id`
178            for other memberships.
179
180        Parameters
181        ----------
182        id: `int`
183            The user id.
184
185        Returns
186        -------
187        `aiobungie.crates.user.BungieUser`
188            A Bungie user.
189
190        Raises
191        ------
192        `aiobungie.error.NotFound`
193            The user was not found.
194        """
195        payload = await self.rest.fetch_bungie_user(id)
196
197        return self.factory.deserialize_bungie_user(payload)

Fetch a Bungie user by their BungieNet id.

This returns a Bungie user membership only. Take a look at Client.fetch_membership_from_id for other memberships.

Parameters
  • id (int): The user id.
Returns
  • aiobungie.crates.user.BungieUser: A Bungie user.
Raises
async def search_users( self, name: str, /) -> aiobungie.Iterator[aiobungie.crates.user.SearchableDestinyUser]:
199    async def search_users(
200        self, name: str, /
201    ) -> iterators.Iterator[user.SearchableDestinyUser]:
202        """Search for players and return all players that matches the same name.
203
204        Parameters
205        ----------
206        name : `buildins.str`
207            The user name.
208
209        Returns
210        -------
211        `aiobungie.iterators.Iterator[aiobungie.crates.DestinyMembership]`
212            A sequence of destiny memberships.
213        """
214        payload = await self.rest.search_users(name)
215
216        return iterators.Iterator(
217            [
218                self.factory.deserialize_searched_user(user)
219                for user in payload["searchResults"]
220            ]
221        )

Search for players and return all players that matches the same name.

Parameters
  • name (buildins.str): The user name.
Returns
async def fetch_user_themes(self) -> collections.abc.Sequence[aiobungie.crates.user.UserThemes]:
223    async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]:
224        """Fetch all available user themes.
225
226        Returns
227        -------
228        `collections.Sequence[aiobungie.crates.user.UserThemes]`
229            A sequence of user themes.
230        """
231        data = await self.rest.fetch_user_themes()
232
233        return self.factory.deserialize_user_themes(data)

Fetch all available user themes.

Returns
  • collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of user themes.
async def fetch_hard_types( self, credential: int, type: Union[int, aiobungie.CredentialType] = <CredentialType.STEAMID: 12>, /) -> aiobungie.crates.user.HardLinkedMembership:
235    async def fetch_hard_types(
236        self,
237        credential: int,
238        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
239        /,
240    ) -> user.HardLinkedMembership:
241        """Gets any hard linked membership given a credential.
242        Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now.
243        Cross Save aware.
244
245        Parameters
246        ----------
247        credential: `int`
248            A valid SteamID64
249        type: `aiobungie.CredentialType`
250            The credential type. This must not be changed
251            Since its only credential that works "currently"
252
253        Returns
254        -------
255        `aiobungie.crates.user.HardLinkedMembership`
256            Information about the hard linked data.
257        """
258
259        payload = await self.rest.fetch_hardlinked_credentials(credential, type)
260
261        return user.HardLinkedMembership(
262            id=int(payload["membershipId"]),
263            type=enums.MembershipType(payload["membershipType"]),
264            cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]),
265        )

Gets any hard linked membership given a credential. Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now. Cross Save aware.

Parameters
  • credential (int): A valid SteamID64
  • type (aiobungie.CredentialType): The credential type. This must not be changed Since its only credential that works "currently"
Returns
  • aiobungie.crates.user.HardLinkedMembership: Information about the hard linked data.
async def fetch_membership_from_id( self, id: int, /, type: Union[int, aiobungie.MembershipType] = <MembershipType.NONE: 0>) -> aiobungie.crates.user.User:
267    async def fetch_membership_from_id(
268        self,
269        id: int,
270        /,
271        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
272    ) -> user.User:
273        """Fetch Bungie user's memberships from their id.
274
275        Notes
276        -----
277        * This returns both BungieNet membership and a sequence of the player's DestinyMemberships
278        Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
279        see `aiobungie.crates.user.DestinyMembership` for more details.
280        * If you only want the bungie user. Consider using `Client.fetch_user` method.
281
282        Parameters
283        ----------
284        id : `int`
285            The user's id.
286        type : `aiobungie.MembershipType`
287            The user's membership type.
288
289        Returns
290        -------
291        `aiobungie.crates.User`
292            A Bungie user with their membership types.
293
294        Raises
295        ------
296        aiobungie.NotFound
297            The requested user was not found.
298        """
299        payload = await self.rest.fetch_membership_from_id(id, type)
300
301        return self.factory.deserialize_user(payload)

Fetch Bungie user's memberships from their id.

Notes
  • This returns both BungieNet membership and a sequence of the player's DestinyMemberships Which includes Stadia, Xbox, Steam and PSN memberships if the player has them, see aiobungie.crates.user.DestinyMembership for more details.
  • If you only want the bungie user. Consider using Client.fetch_user method.
Parameters
Returns
Raises
async def fetch_user_credentials( self, access_token: str, membership_id: int, /) -> collections.abc.Sequence[aiobungie.crates.user.UserCredentials]:
303    async def fetch_user_credentials(
304        self, access_token: str, membership_id: int, /
305    ) -> collections.Sequence[user.UserCredentials]:
306        """Fetch an array of credential types attached to the requested account.
307
308        .. note::
309            This method require OAuth2 Bearer access token.
310
311        Parameters
312        ----------
313        access_token : `str`
314            The bearer access token associated with the bungie account.
315        membership_id : `int`
316            The id of the membership to return.
317
318        Returns
319        -------
320        `collections.Sequence[aiobungie.crates.UserCredentials]`
321            A sequence of the attached user credentials.
322
323        Raises
324        ------
325        `aiobungie.Unauthorized`
326            The access token was wrong or no access token passed.
327        """
328        resp = await self.rest.fetch_user_credentials(access_token, membership_id)
329
330        return self.factory.deserialize_user_credentials(resp)

Fetch an array of credential types attached to the requested account.

This method require OAuth2 Bearer access token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • membership_id (int): The id of the membership to return.
Returns
Raises
async def fetch_profile( self, member_id: int, type: Union[int, aiobungie.MembershipType], components: list[aiobungie.ComponentType], auth: Optional[str] = None) -> aiobungie.crates.components.Component:
334    async def fetch_profile(
335        self,
336        member_id: int,
337        type: typedefs.IntAnd[enums.MembershipType],
338        components: list[enums.ComponentType],
339        auth: typing.Optional[str] = None,
340    ) -> components.Component:
341        """
342        Fetch a bungie profile passing components to the request.
343
344        Parameters
345        ----------
346        member_id: `int`
347            The member's id.
348        type: `aiobungie.MembershipType`
349            A valid membership type.
350        components : `list[aiobungie.ComponentType]`
351            List of profile components to collect and return.
352
353        Other Parameters
354        ----------------
355        auth : `typing.Optional[str]`
356            A Bearer access_token to make the request with.
357            This is optional and limited to components that only requires an Authorization token.
358
359        Returns
360        --------
361        `aiobungie.crates.Component`
362            A Destiny 2 player profile with its components.
363            Only passed components will be available if they exists. Otherwise they will be `None`
364
365        Raises
366        ------
367        `aiobungie.MembershipTypeError`
368            The provided membership type was invalid.
369        """
370        data = await self.rest.fetch_profile(member_id, type, components, auth)
371        return self.factory.deserialize_components(data)

Fetch a bungie profile passing components to the request.

Parameters
Other Parameters
  • auth (typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
  • aiobungie.crates.Component: A Destiny 2 player profile with its components. Only passed components will be available if they exists. Otherwise they will be None
Raises
async def fetch_linked_profiles( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, all: bool = False) -> aiobungie.crates.profile.LinkedProfile:
373    async def fetch_linked_profiles(
374        self,
375        member_id: int,
376        member_type: typedefs.IntAnd[enums.MembershipType],
377        /,
378        *,
379        all: bool = False,
380    ) -> profile.LinkedProfile:
381        """Returns a summary information about all profiles linked to the requested member.
382
383        The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
384
385        .. note::
386            It will only return linked accounts whose linkages you are allowed to view.
387
388        Parameters
389        ----------
390        member_id : `int`
391            The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
392        member_type : `aiobungie.MembershipType`
393            The type for the membership whose linked Destiny account you want to return.
394
395        Other Parameters
396        ----------------
397        all : `bool`
398            If provided and set to `True`, All memberships regardless
399            of whether they're obscured by overrides will be returned,
400
401            If provided and set to `False`, Only available memberships will be returned.
402            The default for this is `False`.
403
404        Returns
405        -------
406        `aiobungie.crates.profile.LinkedProfile`
407            A linked profile object.
408        """
409        resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all)
410
411        return self.factory.deserialize_linked_profiles(resp)

Returns a summary information about all profiles linked to the requested member.

The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.

It will only return linked accounts whose linkages you are allowed to view.

Parameters
  • member_id (int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
  • member_type (aiobungie.MembershipType): The type for the membership whose linked Destiny account you want to return.
Other Parameters
  • all (bool): If provided and set to True, All memberships regardless of whether they're obscured by overrides will be returned,

    If provided and set to False, Only available memberships will be returned. The default for this is False.

Returns
  • aiobungie.crates.profile.LinkedProfile: A linked profile object.
async def fetch_player( self, name: str, code: int, /, type: Union[int, aiobungie.MembershipType] = <MembershipType.ALL: -1>) -> collections.abc.Sequence[aiobungie.crates.user.DestinyMembership]:
413    async def fetch_player(
414        self,
415        name: str,
416        code: int,
417        /,
418        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
419    ) -> collections.Sequence[user.DestinyMembership]:
420        """Fetch a Destiny 2 player's memberships.
421
422        Parameters
423        -----------
424        name: `str`
425            The unique Bungie player name.
426        code : `int`
427            The unique Bungie display name code.
428        type: `aiobungie.internal.enums.MembershipType`
429            The player's membership type, e,g. XBOX, STEAM, PSN
430
431        Returns
432        --------
433        `collections.Sequence[aiobungie.crates.DestinyMembership]`
434            A sequence of the found Destiny 2 player memberships.
435            An empty sequence will be returned if no one found.
436
437        Raises
438        ------
439        `aiobungie.MembershipTypeError`
440            The provided membership type was invalid.
441        """
442        resp = await self.rest.fetch_player(name, code, type)
443
444        return self.factory.deserialize_destiny_memberships(resp)

Fetch a Destiny 2 player's memberships.

Parameters
  • name (str): The unique Bungie player name.
  • code (int): The unique Bungie display name code.
  • type (aiobungie.MembershipType): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
Raises
async def fetch_character( self, member_id: int, membership_type: Union[int, aiobungie.MembershipType], character_id: int, components: list[aiobungie.ComponentType], auth: Optional[str] = None) -> aiobungie.crates.components.CharacterComponent:
446    async def fetch_character(
447        self,
448        member_id: int,
449        membership_type: typedefs.IntAnd[enums.MembershipType],
450        character_id: int,
451        components: list[enums.ComponentType],
452        auth: typing.Optional[str] = None,
453    ) -> components.CharacterComponent:
454        """Fetch a Destiny 2 character.
455
456        Parameters
457        ----------
458        member_id: `int`
459            A valid bungie member id.
460        character_id: `int`
461            The Destiny character id to retrieve.
462        membership_type: `aiobungie.internal.enums.MembershipType`
463            The member's membership type.
464        components: `list[aiobungie.ComponentType]`
465            Multiple arguments of character components to collect and return.
466
467        Other Parameters
468        ----------------
469        auth : `typing.Optional[str]`
470            A Bearer access_token to make the request with.
471            This is optional and limited to components that only requires an Authorization token.
472
473        Returns
474        -------
475        `aiobungie.crates.CharacterComponent`
476            A Bungie character component.
477
478        `aiobungie.MembershipTypeError`
479            The provided membership type was invalid.
480        """
481        resp = await self.rest.fetch_character(
482            member_id, membership_type, character_id, components, auth
483        )
484
485        return self.factory.deserialize_character_component(resp)

Fetch a Destiny 2 character.

Parameters
  • member_id (int): A valid bungie member id.
  • character_id (int): The Destiny character id to retrieve.
  • membership_type (aiobungie.MembershipType): The member's membership type.
  • components (list[aiobungie.ComponentType]): Multiple arguments of character components to collect and return.
Other Parameters
  • auth (typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
async def fetch_unique_weapon_history( self, membership_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> collections.abc.Sequence[aiobungie.crates.activity.ExtendedWeaponValues]:
487    async def fetch_unique_weapon_history(
488        self,
489        membership_id: int,
490        character_id: int,
491        membership_type: typedefs.IntAnd[enums.MembershipType],
492    ) -> collections.Sequence[activity.ExtendedWeaponValues]:
493        """Fetch details about unique weapon usage for a character. Includes all exotics.
494
495        Parameters
496        ----------
497        membership_id : `int`
498            The Destiny user membership id.
499        character_id : `int`
500            The character id to retrieve.
501        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
502            The Destiny user's membership type.
503
504        Returns
505        -------
506        `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]`
507            A sequence of the weapon's extended values.
508        """
509        resp = await self._rest.fetch_unique_weapon_history(
510            membership_id, character_id, membership_type
511        )
512
513        return [
514            self._factory.deserialize_extended_weapon_values(weapon)
515            for weapon in resp["weapons"]
516        ]

Fetch details about unique weapon usage for a character. Includes all exotics.

Parameters
Returns
async def fetch_activities( self, member_id: int, character_id: int, mode: Union[int, aiobungie.GameMode], *, membership_type: Union[int, aiobungie.MembershipType] = <MembershipType.ALL: -1>, page: int = 0, limit: int = 250) -> aiobungie.Iterator[aiobungie.crates.activity.Activity]:
520    async def fetch_activities(
521        self,
522        member_id: int,
523        character_id: int,
524        mode: typedefs.IntAnd[enums.GameMode],
525        *,
526        membership_type: typedefs.IntAnd[
527            enums.MembershipType
528        ] = enums.MembershipType.ALL,
529        page: int = 0,
530        limit: int = 250,
531    ) -> iterators.Iterator[activity.Activity]:
532        """Fetch a Destiny 2 activity for the specified character id.
533
534        Parameters
535        ----------
536        member_id: `int`
537            The user id that starts with `4611`.
538        character_id: `int`
539            The id of the character to retrieve the activities for.
540        mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]`
541            This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
542
543        Other Parameters
544        ----------------
545        membership_type: `aiobungie.internal.enums.MembershipType`
546            The Member ship type, if nothing was passed than it will return all.
547        page: int
548            The page number. Default is `0`
549        limit: int
550            Limit the returned result. Default is `250`.
551
552        Returns
553        -------
554        `aiobungie.iterators.Iterator[aiobungie.crates.Activity]`
555            An iterator of the player's activities.
556
557        Raises
558        ------
559        `aiobungie.MembershipTypeError`
560            The provided membership type was invalid.
561        """
562        resp = await self.rest.fetch_activities(
563            member_id,
564            character_id,
565            mode,
566            membership_type=membership_type,
567            page=page,
568            limit=limit,
569        )
570
571        return self.factory.deserialize_activities(resp)

Fetch a Destiny 2 activity for the specified character id.

Parameters
  • member_id (int): The user id that starts with 4611.
  • character_id (int): The id of the character to retrieve the activities for.
  • mode (aiobungie.typedefs.IntAnd[aiobungie.GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
  • membership_type (aiobungie.MembershipType): The Member ship type, if nothing was passed than it will return all.
  • page (int): The page number. Default is 0
  • limit (int): Limit the returned result. Default is 250.
Returns
Raises
async def fetch_post_activity(self, instance_id: int, /) -> aiobungie.crates.activity.PostActivity:
573    async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity:
574        """Fetch a post activity details.
575
576        Parameters
577        ----------
578        instance_id: `int`
579            The activity instance id.
580
581        Returns
582        -------
583        `aiobungie.crates.PostActivity`
584           A post activity object.
585        """
586        resp = await self.rest.fetch_post_activity(instance_id)
587
588        return self.factory.deserialize_post_activity(resp)

Fetch a post activity details.

Parameters
  • instance_id (int): The activity instance id.
Returns
async def fetch_aggregated_activity_stats( self, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> aiobungie.Iterator[aiobungie.crates.activity.AggregatedActivity]:
590    async def fetch_aggregated_activity_stats(
591        self,
592        character_id: int,
593        membership_id: int,
594        membership_type: typedefs.IntAnd[enums.MembershipType],
595    ) -> iterators.Iterator[activity.AggregatedActivity]:
596        """Fetch aggregated activity stats for a character.
597
598        Parameters
599        ----------
600        character_id: `int`
601            The id of the character to retrieve the activities for.
602        membership_id: `int`
603            The id of the user that started with `4611`.
604        membership_type: `aiobungie.internal.enums.MembershipType`
605            The Member ship type.
606
607        Returns
608        -------
609        `aiobungie.iterators.Iterator[aiobungie.crates.AggregatedActivity]`
610            An iterator of the player's activities.
611
612        Raises
613        ------
614        `aiobungie.MembershipTypeError`
615            The provided membership type was invalid.
616        """
617        resp = await self.rest.fetch_aggregated_activity_stats(
618            character_id, membership_id, membership_type
619        )
620
621        return self.factory.deserialize_aggregated_activities(resp)

Fetch aggregated activity stats for a character.

Parameters
  • character_id (int): The id of the character to retrieve the activities for.
  • membership_id (int): The id of the user that started with 4611.
  • membership_type (aiobungie.MembershipType): The Member ship type.
Returns
Raises
async def fetch_clan_from_id( self, id: int, /, access_token: Optional[str] = None) -> aiobungie.crates.clans.Clan:
625    async def fetch_clan_from_id(
626        self,
627        id: int,
628        /,
629        access_token: typing.Optional[str] = None,
630    ) -> clans.Clan:
631        """Fetch a Bungie Clan by its id.
632
633        Parameters
634        -----------
635        id: `int`
636            The clan id.
637
638        Returns
639        --------
640        `aiobungie.crates.Clan`
641            An Bungie clan.
642
643        Raises
644        ------
645        `aiobungie.NotFound`
646            The clan was not found.
647        """
648        resp = await self.rest.fetch_clan_from_id(id, access_token)
649
650        return self.factory.deserialize_clan(resp)

Fetch a Bungie Clan by its id.

Parameters
  • id (int): The clan id.
Returns
Raises
async def fetch_clan( self, name: str, /, access_token: Optional[str] = None, *, type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> aiobungie.crates.clans.Clan:
652    async def fetch_clan(
653        self,
654        name: str,
655        /,
656        access_token: typing.Optional[str] = None,
657        *,
658        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
659    ) -> clans.Clan:
660        """Fetch a Clan by its name.
661        This method will return the first clan found with given name.
662
663        Parameters
664        ----------
665        name: `str`
666            The clan name
667
668        Other Parameters
669        ----------------
670        access_token : `typing.Optional[str]`
671            An optional access token to make the request with.
672
673            If the token was bound to a member of the clan,
674            This field `aiobungie.crates.Clan.current_user_membership` will be available
675            and will return the membership of the user who made this request.
676        type : `aiobungie.GroupType`
677            The group type, Default is aiobungie.GroupType.CLAN.
678
679        Returns
680        -------
681        `aiobungie.crates.Clan`
682            A Bungie clan.
683
684        Raises
685        ------
686        `aiobungie.NotFound`
687            The clan was not found.
688        """
689        resp = await self.rest.fetch_clan(name, access_token, type=type)
690
691        return self.factory.deserialize_clan(resp)

Fetch a Clan by its name. This method will return the first clan found with given name.

Parameters
  • name (str): The clan name
Other Parameters
Returns
Raises
async def fetch_clan_conversations( self, clan_id: int, /) -> collections.abc.Sequence[aiobungie.crates.clans.ClanConversation]:
693    async def fetch_clan_conversations(
694        self, clan_id: int, /
695    ) -> collections.Sequence[clans.ClanConversation]:
696        """Fetch the conversations/chat channels of the given clan id.
697
698        Parameters
699        ----------
700        clan_id : `int`
701            The clan id.
702
703        Returns
704        `collections.Sequence[aiobungie.crates.ClanConversation]`
705            A sequence of the clan chat channels.
706        """
707        resp = await self.rest.fetch_clan_conversations(clan_id)
708
709        return self.factory.deserialize_clan_conversations(resp)

Fetch the conversations/chat channels of the given clan id.

Parameters
async def fetch_clan_admins( self, clan_id: int, /) -> aiobungie.Iterator[aiobungie.crates.clans.ClanMember]:
711    async def fetch_clan_admins(
712        self, clan_id: int, /
713    ) -> iterators.Iterator[clans.ClanMember]:
714        """Fetch the clan founder and admins.
715
716        Parameters
717        ----------
718        clan_id : `int`
719            The clan id.
720
721        Returns
722        -------
723        `aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]`
724            An iterator over the found clan admins and founder.
725
726        Raises
727        ------
728        `aiobungie.NotFound`
729            The requested clan was not found.
730        """
731        resp = await self.rest.fetch_clan_admins(clan_id)
732
733        return self.factory.deserialize_clan_members(resp)

Fetch the clan founder and admins.

Parameters
  • clan_id (int): The clan id.
Returns
Raises
async def fetch_groups_for_member( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, filter: int = 0, group_type: aiobungie.GroupType = <GroupType.CLAN: 1>) -> collections.abc.Sequence[aiobungie.crates.clans.GroupMember]:
735    async def fetch_groups_for_member(
736        self,
737        member_id: int,
738        member_type: typedefs.IntAnd[enums.MembershipType],
739        /,
740        *,
741        filter: int = 0,
742        group_type: enums.GroupType = enums.GroupType.CLAN,
743    ) -> collections.Sequence[clans.GroupMember]:
744        """Fetch information about the groups that a given member has joined.
745
746        Parameters
747        ----------
748        member_id : `int`
749            The member's id
750        member_type : `aiobungie.MembershipType`
751            The member's membership type.
752
753        Other Parameters
754        ----------------
755        filter : `int`
756            Filter apply to list of joined groups. This Default to `0`
757        group_type : `aiobungie.GroupType`
758            The group's type.
759            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
760
761        Returns
762        -------
763        `collections.Sequence[aiobungie.crates.GroupMember]`
764            A sequence of joined groups for the fetched member.
765        """
766        resp = await self.rest.fetch_groups_for_member(
767            member_id, member_type, filter=filter, group_type=group_type
768        )
769
770        return [
771            self.factory.deserialize_group_member(group) for group in resp["results"]
772        ]

Fetch information about the groups that a given member has joined.

Parameters
Other Parameters
Returns
async def fetch_potential_groups_for_member( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, filter: int = 0, group_type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> collections.abc.Sequence[aiobungie.crates.clans.GroupMember]:
774    async def fetch_potential_groups_for_member(
775        self,
776        member_id: int,
777        member_type: typedefs.IntAnd[enums.MembershipType],
778        /,
779        *,
780        filter: int = 0,
781        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
782    ) -> collections.Sequence[clans.GroupMember]:
783        """Fetch the potential groups for a clan member.
784
785        Parameters
786        ----------
787        member_id : `int`
788            The member's id
789        member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
790            The member's membership type.
791
792        Other Parameters
793        ----------------
794        filter : `int`
795            Filter apply to list of joined groups. This Default to `0`
796        group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]`
797            The group's type.
798            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
799
800        Returns
801        -------
802        `collections.Sequence[aiobungie.crates.GroupMember]`
803            A sequence of joined potential groups for the fetched member.
804        """
805        resp = await self.rest.fetch_potential_groups_for_member(
806            member_id, member_type, filter=filter, group_type=group_type
807        )
808
809        return [
810            self.factory.deserialize_group_member(group) for group in resp["results"]
811        ]

Fetch the potential groups for a clan member.

Parameters
Other Parameters
Returns
async def fetch_clan_members( self, clan_id: int, /, *, name: Optional[str] = None, type: Union[int, aiobungie.MembershipType] = <MembershipType.NONE: 0>) -> aiobungie.Iterator[aiobungie.crates.clans.ClanMember]:
813    async def fetch_clan_members(
814        self,
815        clan_id: int,
816        /,
817        *,
818        name: typing.Optional[str] = None,
819        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
820    ) -> iterators.Iterator[clans.ClanMember]:
821        """Fetch Bungie clan members.
822
823        Parameters
824        ----------
825        clan_id : `int`
826            The clans id
827
828        Other Parameters
829        ----------------
830        name : `typing.Optional[str]`
831            If provided, Only players matching this name will be returned.
832        type : `aiobungie.MembershipType`
833            An optional clan member's membership type.
834            This parameter is used to filter the returned results
835            by the provided membership, For an example XBox memberships only,
836            Otherwise will return all memberships.
837
838        Returns
839        -------
840        `aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]`
841            An iterator over the bungie clan members.
842
843        Raises
844        ------
845        `aiobungie.NotFound`
846            The clan was not found.
847        """
848        resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name)
849
850        return self.factory.deserialize_clan_members(resp)

Fetch Bungie clan members.

Parameters
  • clan_id (int): The clans id
Other Parameters
  • name (typing.Optional[str]): If provided, Only players matching this name will be returned.
  • type (aiobungie.MembershipType): An optional clan member's membership type. This parameter is used to filter the returned results by the provided membership, For an example XBox memberships only, Otherwise will return all memberships.
Returns
Raises
async def fetch_clan_banners(self) -> collections.abc.Sequence[aiobungie.crates.clans.ClanBanner]:
852    async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]:
853        """Fetch the clan banners.
854
855        Returns
856        -------
857        `collections.Sequence[aiobungie.crates.ClanBanner]`
858            A sequence of the clan banners.
859        """
860        resp = await self.rest.fetch_clan_banners()
861
862        return self.factory.deserialize_clan_banners(resp)

Fetch the clan banners.

Returns
async def kick_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> aiobungie.crates.clans.Clan:
865    async def kick_clan_member(
866        self,
867        access_token: str,
868        /,
869        group_id: int,
870        membership_id: int,
871        membership_type: typedefs.IntAnd[enums.MembershipType],
872    ) -> clans.Clan:
873        """Kick a member from the clan.
874
875        .. note::
876            This request requires OAuth2: oauth2: `AdminGroups` scope.
877
878        Parameters
879        ----------
880        access_token : `str`
881            The bearer access token associated with the bungie account.
882        group_id: `int`
883            The group id.
884        membership_id : `int`
885            The member id to kick.
886        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
887            The member's membership type.
888
889        Returns
890        -------
891        `aiobungie.crates.clan.Clan`
892            The clan that the member was kicked from.
893        """
894        resp = await self.rest.kick_clan_member(
895            access_token,
896            group_id=group_id,
897            membership_id=membership_id,
898            membership_type=membership_type,
899        )
900
901        return self.factory.deserialize_clan(resp)

Kick a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to kick.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
  • aiobungie.crates.clan.Clan: The clan that the member was kicked from.
async def fetch_clan_weekly_rewards(self, clan_id: int) -> aiobungie.crates.milestones.Milestone:
903    async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone:
904        """Fetch a Bungie clan's weekly reward state.
905
906        Parameters
907        ----------
908        clan_id : `int`
909            The clan's id.
910
911        Returns
912        -------
913        `aiobungie.crates.Milestone`
914            A runtime status of the clan's milestone data.
915        """
916
917        resp = await self.rest.fetch_clan_weekly_rewards(clan_id)
918
919        return self.factory.deserialize_milestone(resp)

Fetch a Bungie clan's weekly reward state.

Parameters
  • clan_id (int): The clan's id.
Returns
async def fetch_inventory_item(self, hash: int, /) -> aiobungie.crates.entity.InventoryEntity:
923    async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity:
924        """Fetch a static inventory item entity given a its hash.
925
926        Parameters
927        ----------
928        hash: `int`
929            Inventory item's hash.
930
931        Returns
932        -------
933        `aiobungie.crates.InventoryEntity`
934            A bungie inventory item.
935        """
936        resp = await self.rest.fetch_inventory_item(hash)
937
938        return self.factory.deserialize_inventory_entity(resp)

Fetch a static inventory item entity given a its hash.

Parameters
  • hash (int): Inventory item's hash.
Returns
async def fetch_objective_entity(self, hash: int, /) -> aiobungie.crates.entity.ObjectiveEntity:
940    async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity:
941        """Fetch a Destiny objective entity given a its hash.
942
943        Parameters
944        ----------
945        hash: `int`
946            objective's hash.
947
948        Returns
949        -------
950        `aiobungie.crates.ObjectiveEntity`
951            An objective entity item.
952        """
953        resp = await self.rest.fetch_objective_entity(hash)
954
955        return self.factory.deserialize_objective_entity(resp)

Fetch a Destiny objective entity given a its hash.

Parameters
  • hash (int): objective's hash.
Returns
async def search_entities( self, name: str, entity_type: str, *, page: int = 0) -> aiobungie.Iterator[aiobungie.crates.entity.SearchableEntity]:
957    async def search_entities(
958        self, name: str, entity_type: str, *, page: int = 0
959    ) -> iterators.Iterator[entity.SearchableEntity]:
960        """Search for Destiny2 entities given a name and its type.
961
962        Parameters
963        ----------
964        name : `str`
965            The name of the entity, i.e., Thunderlord, One thousand voices.
966        entity_type : `str`
967            The type of the entity, AKA Definition,
968            For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items.
969
970        Other Parameters
971        ----------------
972        page : `int`
973            An optional page to return. Default to 0.
974
975        Returns
976        -------
977        `aiobungie.iterators.Iterator[aiobungie.crates.SearchableEntity]`
978            An iterator over the found results matching the provided name.
979        """
980        resp = await self.rest.search_entities(name, entity_type, page=page)
981
982        return self.factory.deserialize_inventory_results(resp)

Search for Destiny2 entities given a name and its type.

Parameters
  • name (str): The name of the entity, i.e., Thunderlord, One thousand voices.
  • entity_type (str): The type of the entity, AKA Definition, For an example DestinyInventoryItemDefinition for emblems, weapons, and other inventory items.
Other Parameters
  • page (int): An optional page to return. Default to 0.
Returns
async def fetch_fireteams( self, activity_type: Union[int, aiobungie.FireteamActivity], *, platform: Union[int, aiobungie.FireteamPlatform] = <FireteamPlatform.ANY: 0>, language: Union[aiobungie.FireteamLanguage, str] = <FireteamLanguage.ALL: >, date_range: int = 0, page: int = 0, slots_filter: int = 0) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]]:
 986    async def fetch_fireteams(
 987        self,
 988        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
 989        *,
 990        platform: typedefs.IntAnd[
 991            fireteams.FireteamPlatform
 992        ] = fireteams.FireteamPlatform.ANY,
 993        language: typing.Union[
 994            fireteams.FireteamLanguage, str
 995        ] = fireteams.FireteamLanguage.ALL,
 996        date_range: int = 0,
 997        page: int = 0,
 998        slots_filter: int = 0,
 999    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
1000        """Fetch public Bungie fireteams with open slots.
1001
1002        Parameters
1003        ----------
1004        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1005            The fireteam activity type.
1006
1007        Other Parameters
1008        ----------------
1009        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1010            If this is provided. Then the results will be filtered with the given platform.
1011            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1012        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1013            A locale language to filter the used language in that fireteam.
1014            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1015        date_range : `int`
1016            An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`.
1017        page : `int`
1018            The page number. By default its `0` which returns all available activities.
1019        slots_filter : `int`
1020            Filter the returned fireteams based on available slots. Default is `0`
1021
1022        Returns
1023        -------
1024        `typing.Optional[collections.Sequence[fireteams.Fireteam]]`
1025            A sequence of `aiobungie.crates.Fireteam` or `None`.
1026        """
1027
1028        resp = await self.rest.fetch_fireteams(
1029            activity_type,
1030            platform=platform,
1031            language=language,
1032            date_range=date_range,
1033            page=page,
1034            slots_filter=slots_filter,
1035        )
1036
1037        return self.factory.deserialize_fireteams(resp)

Fetch public Bungie fireteams with open slots.

Parameters
Other Parameters
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (int): An integer to filter the date range of the returned fireteams. Defaults to aiobungie.FireteamDate.ALL.
  • page (int): The page number. By default its 0 which returns all available activities.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
async def fetch_avaliable_clan_fireteams( self, access_token: str, group_id: int, activity_type: Union[int, aiobungie.FireteamActivity], *, platform: Union[int, aiobungie.FireteamPlatform], language: Union[aiobungie.FireteamLanguage, str], date_range: int = 0, page: int = 0, public_only: bool = False, slots_filter: int = 0) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]]:
1039    async def fetch_avaliable_clan_fireteams(
1040        self,
1041        access_token: str,
1042        group_id: int,
1043        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1044        *,
1045        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1046        language: typing.Union[fireteams.FireteamLanguage, str],
1047        date_range: int = 0,
1048        page: int = 0,
1049        public_only: bool = False,
1050        slots_filter: int = 0,
1051    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
1052        """Fetch a clan's fireteams with open slots.
1053
1054        .. note::
1055            This method requires OAuth2: ReadGroups scope.
1056
1057        Parameters
1058        ----------
1059        access_token : `str`
1060            The bearer access token associated with the bungie account.
1061        group_id : `int`
1062            The group/clan id of the fireteam.
1063        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1064            The fireteam activity type.
1065
1066        Other Parameters
1067        ----------------
1068        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1069            If this is provided. Then the results will be filtered with the given platform.
1070            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1071        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1072            A locale language to filter the used language in that fireteam.
1073            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1074        date_range : `int`
1075            An integer to filter the date range of the returned fireteams. Defaults to `0`.
1076        page : `int`
1077            The page number. By default its `0` which returns all available activities.
1078        public_only: `bool`
1079            If set to True, Then only public fireteams will be returned.
1080        slots_filter : `int`
1081            Filter the returned fireteams based on available slots. Default is `0`
1082
1083        Returns
1084        -------
1085        `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]`
1086            A sequence of  fireteams found in the clan.
1087            `None` will be returned if nothing was found.
1088        """
1089        resp = await self.rest.fetch_avaliable_clan_fireteams(
1090            access_token,
1091            group_id,
1092            activity_type,
1093            platform=platform,
1094            language=language,
1095            date_range=date_range,
1096            page=page,
1097            public_only=public_only,
1098            slots_filter=slots_filter,
1099        )
1100
1101        return self.factory.deserialize_fireteams(resp)

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id of the fireteam.
  • activity_type (aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (int): An integer to filter the date range of the returned fireteams. Defaults to 0.
  • page (int): The page number. By default its 0 which returns all available activities.
  • public_only (bool): If set to True, Then only public fireteams will be returned.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
  • typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]: A sequence of fireteams found in the clan. None will be returned if nothing was found.
async def fetch_clan_fireteam( self, access_token: str, fireteam_id: int, group_id: int) -> aiobungie.crates.fireteams.AvailableFireteam:
1103    async def fetch_clan_fireteam(
1104        self, access_token: str, fireteam_id: int, group_id: int
1105    ) -> fireteams.AvailableFireteam:
1106        """Fetch a specific clan fireteam.
1107
1108        .. note::
1109            This method requires OAuth2: ReadGroups scope.
1110
1111        Parameters
1112        ----------
1113        access_token : `str`
1114            The bearer access token associated with the bungie account.
1115        group_id : `int`
1116            The group/clan id to fetch the fireteam from.
1117        fireteam_id : `int`
1118            The fireteam id to fetch.
1119
1120        Returns
1121        -------
1122        `typing.Optional[aiobungie.crates.AvailableFireteam]`
1123            A sequence of available fireteams objects if exists. else `None` will be returned.
1124        """
1125        resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id)
1126
1127        return self.factory.deserialize_available_fireteams(
1128            resp, no_results=True
1129        )  # type: ignore[return-value]

Fetch a specific clan fireteam.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch the fireteam from.
  • fireteam_id (int): The fireteam id to fetch.
Returns
async def fetch_my_clan_fireteams( self, access_token: str, group_id: int, *, include_closed: bool = True, platform: Union[int, aiobungie.FireteamPlatform], language: Union[aiobungie.FireteamLanguage, str], filtered: bool = True, page: int = 0) -> collections.abc.Sequence[aiobungie.crates.fireteams.AvailableFireteam]:
1131    async def fetch_my_clan_fireteams(
1132        self,
1133        access_token: str,
1134        group_id: int,
1135        *,
1136        include_closed: bool = True,
1137        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1138        language: typing.Union[fireteams.FireteamLanguage, str],
1139        filtered: bool = True,
1140        page: int = 0,
1141    ) -> collections.Sequence[fireteams.AvailableFireteam]:
1142        """A method that's similar to `fetch_fireteams` but requires OAuth2.
1143
1144        .. note::
1145            This method requires OAuth2: ReadGroups scope.
1146
1147        Parameters
1148        ----------
1149        access_token : str
1150            The bearer access token associated with the bungie account.
1151        group_id : int
1152            The group/clan id to fetch.
1153
1154        Other Parameters
1155        ----------------
1156        include_closed : bool
1157            If provided and set to True, It will also return closed fireteams.
1158            If provided and set to False, It will only return public fireteams. Default is True.
1159        platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]
1160            If this is provided. Then the results will be filtered with the given platform.
1161            Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
1162        language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]
1163            A locale language to filter the used language in that fireteam.
1164            Defaults to aiobungie.crates.FireteamLanguage.ALL
1165        filtered : bool
1166            If set to True, it will filter by clan. Otherwise not. Default is True.
1167        page : int
1168            The page number. By default its 0 which returns all available activities.
1169
1170        Returns
1171        -------
1172        `collections.Sequence[aiobungie.crates.AvailableFireteam]`
1173            A sequence of available fireteams objects if exists. else `None` will be returned.
1174        """
1175        resp = await self.rest.fetch_my_clan_fireteams(
1176            access_token,
1177            group_id,
1178            include_closed=include_closed,
1179            platform=platform,
1180            language=language,
1181            filtered=filtered,
1182            page=page,
1183        )
1184
1185        return self.factory.deserialize_available_fireteams(resp)  # type: ignore[return-value]

A method that's similar to fetch_fireteams but requires OAuth2.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch.
Other Parameters
  • include_closed (bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True.
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • filtered (bool): If set to True, it will filter by clan. Otherwise not. Default is True.
  • page (int): The page number. By default its 0 which returns all available activities.
Returns
async def fetch_friends( self, access_token: str, /) -> collections.abc.Sequence[aiobungie.crates.friends.Friend]:
1189    async def fetch_friends(
1190        self, access_token: str, /
1191    ) -> collections.Sequence[friends.Friend]:
1192        """Fetch bungie friend list.
1193
1194        .. note::
1195            This requests OAuth2: ReadUserData scope.
1196
1197        Parameters
1198        -----------
1199        access_token : `str`
1200            The bearer access token associated with the bungie account.
1201
1202        Returns
1203        -------
1204        `collections.Sequence[aiobungie.crates.Friend]`
1205            A sequence of the friends associated with that access token.
1206        """
1207
1208        resp = await self.rest.fetch_friends(access_token)
1209
1210        return self.factory.deserialize_friends(resp)

Fetch bungie friend list.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_friend_requests(self, access_token: str, /) -> aiobungie.crates.friends.FriendRequestView:
1212    async def fetch_friend_requests(
1213        self, access_token: str, /
1214    ) -> friends.FriendRequestView:
1215        """Fetch pending bungie friend requests queue.
1216
1217        .. note::
1218            This requests OAuth2: ReadUserData scope.
1219
1220        Parameters
1221        -----------
1222        access_token : `str`
1223            The bearer access token associated with the bungie account.
1224
1225        Returns
1226        -------
1227        `aiobungie.crates.FriendRequestView`
1228            A friend requests view of that associated access token.
1229        """
1230
1231        resp = await self.rest.fetch_friend_requests(access_token)
1232
1233        return self.factory.deserialize_friend_requests(resp)

Fetch pending bungie friend requests queue.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_application(self, appid: int, /) -> aiobungie.crates.application.Application:
1237    async def fetch_application(self, appid: int, /) -> application.Application:
1238        """Fetch a Bungie application.
1239
1240        Parameters
1241        -----------
1242        appid: `int`
1243            The application id.
1244
1245        Returns
1246        --------
1247        `aiobungie.crates.Application`
1248            A Bungie application.
1249        """
1250        resp = await self.rest.fetch_application(appid)
1251
1252        return self.factory.deserialize_app(resp)

Fetch a Bungie application.

Parameters
  • appid (int): The application id.
Returns
async def fetch_public_milestone_content( self, milestone_hash: int, /) -> aiobungie.crates.milestones.MilestoneContent:
1256    async def fetch_public_milestone_content(
1257        self, milestone_hash: int, /
1258    ) -> milestones.MilestoneContent:
1259        """Fetch the milestone content given its hash.
1260
1261        Parameters
1262        ----------
1263        milestone_hash : `int`
1264            The milestone hash.
1265
1266        Returns
1267        -------
1268        `aiobungie.crates.milestones.MilestoneContent`
1269            A milestone content object.
1270        """
1271        resp = await self.rest.fetch_public_milestone_content(milestone_hash)
1272
1273        return self.factory.deserialize_public_milestone_content(resp)

Fetch the milestone content given its hash.

Parameters
  • milestone_hash (int): The milestone hash.
Returns
  • aiobungie.crates.milestones.MilestoneContent: A milestone content object.
@typing.final
class ClosedReasons(aiobungie.Flag):
779@typing.final
780class ClosedReasons(Flag):
781    """A Flags enumeration representing the reasons why a person can't join this user's fireteam."""
782
783    NONE = 0
784    MATCHMAKING = 1 << 0
785    LOADING = 1 << 1
786    SOLO = 1 << 2
787    """The activity is required to be played solo."""
788    INTERNAL_REASONS = 1 << 3
789    """
790    The user can't be joined for one of a variety of internal reasons.
791    Basically, the game can't let you join at this time,
792    but for reasons that aren't under the control of this user
793    """
794    DISALLOWED_BY_GAME_STATE = 1 << 4
795    """The user's current activity/quest/other transitory game state is preventing joining."""
796    OFFLINE = 32768
797    """The user appears offline."""

A Flags enumeration representing the reasons why a person can't join this user's fireteam.

NONE = <ClosedReasons.NONE: 0>
MATCHMAKING = <ClosedReasons.MATCHMAKING: 1>
LOADING = <ClosedReasons.LOADING: 2>
SOLO = <ClosedReasons.SOLO: 4>

The activity is required to be played solo.

INTERNAL_REASONS = <ClosedReasons.INTERNAL_REASONS: 8>

The user can't be joined for one of a variety of internal reasons. Basically, the game can't let you join at this time, but for reasons that aren't under the control of this user

DISALLOWED_BY_GAME_STATE = <ClosedReasons.DISALLOWED_BY_GAME_STATE: 16>

The user's current activity/quest/other transitory game state is preventing joining.

OFFLINE = <ClosedReasons.OFFLINE: 32768>

The user appears offline.

Inherited Members
Flag
name
value
@typing.final
class ComponentFields(aiobungie.Enum):
74@typing.final
75class ComponentFields(enums.Enum):
76    """An enum that provides fields found in a base component response."""
77
78    PRIVACY = ComponentPrivacy
79    DISABLED = False

An enum that provides fields found in a base component response.

PRIVACY = <ComponentFields.PRIVACY: <enum 'ComponentPrivacy'>>
DISABLED = <ComponentFields.DISABLED: False>
Inherited Members
Enum
name
value
@typing.final
class ComponentPrivacy(builtins.int, aiobungie.Enum):
65@typing.final
66class ComponentPrivacy(int, enums.Enum):
67    """An enum the provides privacy settings for profile components."""
68
69    NONE = 0
70    PUBLIC = 1
71    PRIVATE = 2

An enum the provides privacy settings for profile components.

NONE = <ComponentPrivacy.NONE: 0>
PUBLIC = <ComponentPrivacy.PUBLIC: 1>
PRIVATE = <ComponentPrivacy.PRIVATE: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ComponentType(aiobungie.Enum):
358@typing.final
359class ComponentType(Enum):
360    """An Enum for Destiny 2 profile Components."""
361
362    NONE = 0
363
364    PROFILE = 100
365    PROFILE_INVENTORIES = 102
366    PROFILE_CURRENCIES = 103
367    PROFILE_PROGRESSION = 104
368    ALL_PROFILES = (
369        PROFILE,
370        PROFILE_INVENTORIES,
371        PROFILE_CURRENCIES,
372        PROFILE_PROGRESSION,
373    )
374    """All profile components."""
375
376    VENDORS = 400
377    VENDOR_SALES = 402
378    VENDOR_RECEIPTS = 101
379    ALL_VENDORS = (VENDORS, VENDOR_RECEIPTS, VENDOR_SALES)
380    """All vendor components."""
381
382    # Items
383    ITEM_INSTANCES = 300
384    ITEM_OBJECTIVES = 301
385    ITEM_PERKS = 302
386    ITEM_RENDER_DATA = 303
387    ITEM_STATS = 304
388    ITEM_SOCKETS = 305
389    ITEM_TALENT_GRINDS = 306
390    ITEM_PLUG_STATES = 308
391    ITEM_PLUG_OBJECTIVES = 309
392    ITEM_REUSABLE_PLUGS = 310
393
394    ALL_ITEMS = (
395        ITEM_PLUG_OBJECTIVES,
396        ITEM_PLUG_STATES,
397        ITEM_SOCKETS,
398        ITEM_INSTANCES,
399        ITEM_OBJECTIVES,
400        ITEM_PERKS,
401        ITEM_RENDER_DATA,
402        ITEM_STATS,
403        ITEM_TALENT_GRINDS,
404        ITEM_REUSABLE_PLUGS,
405    )
406    """All item components."""
407
408    PLATFORM_SILVER = 105
409    KIOSKS = 500
410    CURRENCY_LOOKUPS = 600
411    PRESENTATION_NODES = 700
412    COLLECTIBLES = 800
413    RECORDS = 900
414    TRANSITORY = 1000
415    METRICS = 1100
416    INVENTORIES = 102
417    STRING_VARIABLES = 1200
418    CRAFTABLES = 1300
419
420    CHARACTERS = 200
421    CHARACTER_INVENTORY = 201
422    CHARECTER_PROGRESSION = 202
423    CHARACTER_RENDER_DATA = 203
424    CHARACTER_ACTIVITIES = 204
425    CHARACTER_EQUIPMENT = 205
426
427    ALL_CHARACTERS = (
428        CHARACTERS,
429        CHARACTER_INVENTORY,
430        CHARECTER_PROGRESSION,
431        CHARACTER_RENDER_DATA,
432        CHARACTER_ACTIVITIES,
433        CHARACTER_EQUIPMENT,
434        RECORDS,
435    )
436    """All character components."""
437
438    ALL = (
439        *ALL_PROFILES,  # type: ignore
440        *ALL_CHARACTERS,  # type: ignore
441        *ALL_VENDORS,  # type: ignore
442        *ALL_ITEMS,  # type: ignore
443        RECORDS,
444        CURRENCY_LOOKUPS,
445        PRESENTATION_NODES,
446        COLLECTIBLES,
447        KIOSKS,
448        METRICS,
449        PLATFORM_SILVER,
450        INVENTORIES,
451        STRING_VARIABLES,
452        TRANSITORY,
453        CRAFTABLES,
454    )
455    """ALl components included."""

An Enum for Destiny 2 profile Components.

NONE = <ComponentType.NONE: 0>
PROFILE = <ComponentType.PROFILE: 100>
PROFILE_INVENTORIES = <ComponentType.PROFILE_INVENTORIES: 102>
PROFILE_CURRENCIES = <ComponentType.PROFILE_CURRENCIES: 103>
PROFILE_PROGRESSION = <ComponentType.PROFILE_PROGRESSION: 104>
ALL_PROFILES = <ComponentType.ALL_PROFILES: (100, 102, 103, 104)>

All profile components.

VENDORS = <ComponentType.VENDORS: 400>
VENDOR_SALES = <ComponentType.VENDOR_SALES: 402>
VENDOR_RECEIPTS = <ComponentType.VENDOR_RECEIPTS: 101>
ALL_VENDORS = <ComponentType.ALL_VENDORS: (400, 101, 402)>

All vendor components.

ITEM_INSTANCES = <ComponentType.ITEM_INSTANCES: 300>
ITEM_OBJECTIVES = <ComponentType.ITEM_OBJECTIVES: 301>
ITEM_PERKS = <ComponentType.ITEM_PERKS: 302>
ITEM_RENDER_DATA = <ComponentType.ITEM_RENDER_DATA: 303>
ITEM_STATS = <ComponentType.ITEM_STATS: 304>
ITEM_SOCKETS = <ComponentType.ITEM_SOCKETS: 305>
ITEM_TALENT_GRINDS = <ComponentType.ITEM_TALENT_GRINDS: 306>
ITEM_PLUG_STATES = <ComponentType.ITEM_PLUG_STATES: 308>
ITEM_PLUG_OBJECTIVES = <ComponentType.ITEM_PLUG_OBJECTIVES: 309>
ITEM_REUSABLE_PLUGS = <ComponentType.ITEM_REUSABLE_PLUGS: 310>
ALL_ITEMS = <ComponentType.ALL_ITEMS: (309, 308, 305, 300, 301, 302, 303, 304, 306, 310)>

All item components.

PLATFORM_SILVER = <ComponentType.PLATFORM_SILVER: 105>
KIOSKS = <ComponentType.KIOSKS: 500>
CURRENCY_LOOKUPS = <ComponentType.CURRENCY_LOOKUPS: 600>
PRESENTATION_NODES = <ComponentType.PRESENTATION_NODES: 700>
COLLECTIBLES = <ComponentType.COLLECTIBLES: 800>
RECORDS = <ComponentType.RECORDS: 900>
TRANSITORY = <ComponentType.TRANSITORY: 1000>
METRICS = <ComponentType.METRICS: 1100>
INVENTORIES = <ComponentType.PROFILE_INVENTORIES: 102>
STRING_VARIABLES = <ComponentType.STRING_VARIABLES: 1200>
CRAFTABLES = <ComponentType.CRAFTABLES: 1300>
CHARACTERS = <ComponentType.CHARACTERS: 200>
CHARACTER_INVENTORY = <ComponentType.CHARACTER_INVENTORY: 201>
CHARECTER_PROGRESSION = <ComponentType.CHARECTER_PROGRESSION: 202>
CHARACTER_RENDER_DATA = <ComponentType.CHARACTER_RENDER_DATA: 203>
CHARACTER_ACTIVITIES = <ComponentType.CHARACTER_ACTIVITIES: 204>
CHARACTER_EQUIPMENT = <ComponentType.CHARACTER_EQUIPMENT: 205>
ALL_CHARACTERS = <ComponentType.ALL_CHARACTERS: (200, 201, 202, 203, 204, 205, 900)>

All character components.

ALL = <ComponentType.ALL: (100, 102, 103, 104, 200, 201, 202, 203, 204, 205, 900, 400, 101, 402, 309, 308, 305, 300, 301, 302, 303, 304, 306, 310, 900, 600, 700, 800, 500, 1100, 105, 102, 1200, 1000, 1300)>

ALl components included.

Inherited Members
Enum
name
value
@typing.final
class CredentialType(builtins.int, aiobungie.Enum):
661@typing.final
662class CredentialType(int, Enum):
663    """The types of the accounts system supports at bungie."""
664
665    NONE = 0
666    XUID = 1
667    PSNID = 2
668    WILD = 3
669    FAKE = 4
670    FACEBOOK = 5
671    GOOGLE = 8
672    WINDOWS = 9
673    DEMONID = 10
674    STEAMID = 12
675    BATTLENETID = 14
676    STADIAID = 16
677    TWITCHID = 18

The types of the accounts system supports at bungie.

NONE = <CredentialType.NONE: 0>
XUID = <CredentialType.XUID: 1>
PSNID = <CredentialType.PSNID: 2>
WILD = <CredentialType.WILD: 3>
FAKE = <CredentialType.FAKE: 4>
FACEBOOK = <CredentialType.FACEBOOK: 5>
GOOGLE = <CredentialType.GOOGLE: 8>
WINDOWS = <CredentialType.WINDOWS: 9>
DEMONID = <CredentialType.DEMONID: 10>
STEAMID = <CredentialType.STEAMID: 12>
BATTLENETID = <CredentialType.BATTLENETID: 14>
STADIAID = <CredentialType.STADIAID: 16>
TWITCHID = <CredentialType.TWITCHID: 18>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class DamageType(builtins.int, aiobungie.Enum):
539@typing.final
540class DamageType(int, Enum):
541    """Enums for Destiny Damage types"""
542
543    NONE = 0
544    KINETIC = 1
545    ARC = 2
546    SOLAR = 3
547    VOID = 4
548    RAID = 5
549    """This is a special damage type reserved for some raid activity encounters."""
550    STASIS = 6

Enums for Destiny Damage types

NONE = <DamageType.NONE: 0>
KINETIC = <DamageType.KINETIC: 1>
ARC = <DamageType.ARC: 2>
SOLAR = <DamageType.SOLAR: 3>
VOID = <DamageType.VOID: 4>
RAID = <DamageType.RAID: 5>

This is a special damage type reserved for some raid activity encounters.

STASIS = <DamageType.STASIS: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Difficulty(builtins.int, aiobungie.Enum):
64@typing.final
65class Difficulty(int, enums.Enum):
66    """An enum for activities difficulties."""
67
68    TRIVIAL = 0
69    EASY = 1
70    NORMAL = 2
71    CHALLENGING = 3
72    HARD = 4
73    BRAVE = 5
74    ALMOST_IMPOSSIBLE = 6
75    IMPOSSIBLE = 7

An enum for activities difficulties.

TRIVIAL = <Difficulty.TRIVIAL: 0>
EASY = <Difficulty.EASY: 1>
NORMAL = <Difficulty.NORMAL: 2>
CHALLENGING = <Difficulty.CHALLENGING: 3>
HARD = <Difficulty.HARD: 4>
BRAVE = <Difficulty.BRAVE: 5>
ALMOST_IMPOSSIBLE = <Difficulty.ALMOST_IMPOSSIBLE: 6>
IMPOSSIBLE = <Difficulty.IMPOSSIBLE: 7>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Dungeon(builtins.int, aiobungie.Enum):
160@typing.final
161class Dungeon(int, Enum):
162    """An Enum for all available Dungeon/Like missions in Destiny 2."""
163
164    NORMAL_PRESAGE = 2124066889
165    """Normal Presage"""
166
167    MASTER_PRESAGE = 4212753278
168    """Master Presage"""
169
170    HARBINGER = 1738383283
171    """Harbinger"""
172
173    PROPHECY = 4148187374
174    """Prophecy"""
175
176    MASTER_POH = 785700673
177    """Master Pit of Heresy?"""
178
179    LEGEND_POH = 785700678
180    """Legend Pit of Heresy?"""
181
182    POH = 1375089621
183    """Normal Pit of Heresy."""
184
185    SHATTERED = 2032534090
186    """Shattered Throne"""
187
188    GOA_LEGEND = 4078656646
189    """Grasp of Avarice legend."""
190
191    GOA_MASTER = 3774021532
192    """Grasp of Avarice master."""

An Enum for all available Dungeon/Like missions in Destiny 2.

NORMAL_PRESAGE = <Dungeon.NORMAL_PRESAGE: 2124066889>

Normal Presage

MASTER_PRESAGE = <Dungeon.MASTER_PRESAGE: 4212753278>

Master Presage

HARBINGER = <Dungeon.HARBINGER: 1738383283>

Harbinger

PROPHECY = <Dungeon.PROPHECY: 4148187374>

Prophecy

MASTER_POH = <Dungeon.MASTER_POH: 785700673>

Master Pit of Heresy?

LEGEND_POH = <Dungeon.LEGEND_POH: 785700678>

Legend Pit of Heresy?

POH = <Dungeon.POH: 1375089621>

Normal Pit of Heresy.

SHATTERED = <Dungeon.SHATTERED: 2032534090>

Shattered Throne

GOA_LEGEND = <Dungeon.GOA_LEGEND: 4078656646>

Grasp of Avarice legend.

GOA_MASTER = <Dungeon.GOA_MASTER: 3774021532>

Grasp of Avarice master.

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class Enum(enum.Enum):
72class Enum(__enum.Enum):
73    """Builtin Python enum with extra handlings."""
74
75    @property
76    def name(self) -> str:  # type: ignore[override]
77        return self._name_
78
79    @property
80    def value(self) -> typing.Any:  # type: ignore[override]
81        return self._value_
82
83    def __str__(self) -> str:
84        return self._name_
85
86    def __repr__(self) -> str:
87        return f"<{type(self).__name__}.{self._name_}: {self._value_!s}>"
88
89    def __int__(self) -> int:
90        if isinstance(self.value, _ITERABLE):
91            raise TypeError(
92                f"Can't overload {self.value} in {type(self).__name__}, Please use `.value` attribute.",
93            )
94        return int(self.value)

Builtin Python enum with extra handlings.

name: str

The name of the Enum member.

value: Any

The value of the Enum member.

class Factory(aiobungie.interfaces.factory.FactoryInterface):
  61class Factory(interfaces.FactoryInterface):
  62    """The base deserialization factory class for all aiobungie objects.
  63
  64    Highly inspired hikari entity factory used to deserialize JSON responses from the REST client and turning them
  65    into a `aiobungie.crates` Python classes.
  66    """
  67
  68    __slots__ = ("_net",)
  69
  70    def __init__(self, net: traits.Netrunner) -> None:
  71        self._net = net
  72
  73    def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser:
  74        return user.BungieUser(
  75            id=int(data["membershipId"]),
  76            created_at=time.clean_date(data["firstAccess"]),
  77            name=data.get("cachedBungieGlobalDisplayName", undefined.UNDEFINED),
  78            is_deleted=data["isDeleted"],
  79            about=data["about"],
  80            updated_at=time.clean_date(data["lastUpdate"]),
  81            psn_name=data.get("psnDisplayName", None),
  82            stadia_name=data.get("stadiaDisplayName", None),
  83            steam_name=data.get("steamDisplayName", None),
  84            twitch_name=data.get("twitchDisplayName", None),
  85            blizzard_name=data.get("blizzardDisplayName", None),
  86            status=data["statusText"],
  87            locale=data["locale"],
  88            picture=assets.Image(path=str(data["profilePicturePath"])),
  89            code=data.get("cachedBungieGlobalDisplayNameCode", None),
  90            unique_name=data.get("uniqueName", None),
  91            theme_id=int(data["profileTheme"]),
  92            show_activity=bool(data["showActivity"]),
  93            theme_name=data["profileThemeName"],
  94            display_title=data["userTitleDisplay"],
  95        )
  96
  97    def deserialize_partial_bungie_user(
  98        self, payload: typedefs.JSONObject
  99    ) -> user.PartialBungieUser:
 100        return user.PartialBungieUser(
 101            net=self._net,
 102            types=[
 103                enums.MembershipType(type_)
 104                for type_ in payload.get("applicableMembershipTypes", [])
 105            ],
 106            name=payload.get("displayName", undefined.UNDEFINED),
 107            id=int(payload["membershipId"]),
 108            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
 109            is_public=payload["isPublic"],
 110            icon=assets.Image(payload.get("iconPath", "")),
 111            type=enums.MembershipType(payload["membershipType"]),
 112        )
 113
 114    def deserialize_destiny_membership(
 115        self, payload: typedefs.JSONObject
 116    ) -> user.DestinyMembership:
 117        name: undefined.UndefinedOr[str] = undefined.UNDEFINED
 118        if (
 119            raw_name := payload.get("bungieGlobalDisplayName", "")
 120        ) and not typedefs.is_unknown(raw_name):
 121            name = raw_name
 122
 123        return user.DestinyMembership(
 124            net=self._net,
 125            id=int(payload["membershipId"]),
 126            name=name,
 127            code=payload.get("bungieGlobalDisplayNameCode", None),
 128            last_seen_name=payload.get("LastSeenDisplayName")
 129            or payload.get("displayName")  # noqa: W503
 130            or "",  # noqa: W503
 131            type=enums.MembershipType(payload["membershipType"]),
 132            is_public=payload["isPublic"],
 133            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
 134            icon=assets.Image(payload.get("iconPath", "")),
 135            types=[
 136                enums.MembershipType(type_)
 137                for type_ in payload.get("applicableMembershipTypes", [])
 138            ],
 139        )
 140
 141    def deserialize_destiny_memberships(
 142        self, data: typedefs.JSONArray
 143    ) -> collections.Sequence[user.DestinyMembership]:
 144        return [self.deserialize_destiny_membership(membership) for membership in data]
 145
 146    def deserialize_user(self, data: typedefs.JSONObject) -> user.User:
 147
 148        primary_membership_id: typing.Optional[int] = None
 149        if raw_primary_id := data.get("primaryMembershipId"):
 150            primary_membership_id = int(raw_primary_id)
 151
 152        return user.User(
 153            bungie=self.deserialize_bungie_user(data["bungieNetUser"]),
 154            destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]),
 155            primary_membership_id=primary_membership_id,
 156        )
 157
 158    def deserialize_searched_user(
 159        self, payload: typedefs.JSONObject
 160    ) -> user.SearchableDestinyUser:
 161        name: undefined.UndefinedOr[str] = undefined.UNDEFINED
 162        if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown(
 163            raw_name
 164        ):
 165            name = raw_name
 166
 167        code: typing.Optional[int] = None
 168        if raw_code := payload.get("bungieGlobalDisplayNameCode"):
 169            code = int(raw_code)
 170
 171        bungie_id: typing.Optional[int] = None
 172        if raw_bungie_id := payload.get("bungieNetMembershipId"):
 173            bungie_id = int(raw_bungie_id)
 174
 175        return user.SearchableDestinyUser(
 176            name=name,
 177            code=code,
 178            bungie_id=bungie_id,
 179            memberships=self.deserialize_destiny_memberships(
 180                payload["destinyMemberships"]
 181            ),
 182        )
 183
 184    def deserialize_user_credentials(
 185        self, payload: typedefs.JSONArray
 186    ) -> collections.Sequence[user.UserCredentials]:
 187        return [
 188            user.UserCredentials(
 189                type=enums.CredentialType(int(creds["credentialType"])),
 190                display_name=creds["credentialDisplayName"],
 191                is_public=creds["isPublic"],
 192                self_as_string=creds.get("credentialAsString", undefined.UNDEFINED),
 193            )
 194            for creds in payload
 195        ]
 196
 197    def deserialize_user_themes(
 198        self, payload: typedefs.JSONArray
 199    ) -> collections.Sequence[user.UserThemes]:
 200        return [
 201            user.UserThemes(
 202                id=int(entry["userThemeId"]),
 203                name=entry["userThemeName"]
 204                if "userThemeName" in entry
 205                else undefined.UNDEFINED,
 206                description=entry["userThemeDescription"]
 207                if "userThemeDescription" in entry
 208                else undefined.UNDEFINED,
 209            )
 210            for entry in payload
 211        ]
 212
 213    def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan:
 214
 215        # This is kinda redundant
 216        data = payload
 217
 218        # This is always outside the details.
 219        current_user_map: typing.Optional[
 220            collections.Mapping[str, clans.ClanMember]
 221        ] = None
 222        if raw_current_user_map := payload.get("currentUserMemberMap"):
 223            current_user_map = {
 224                membership_type: self.deserialize_clan_member(membership)
 225                for membership_type, membership in raw_current_user_map.items()
 226            }
 227
 228        try:
 229            data = payload["detail"]
 230        except KeyError:
 231            pass
 232
 233        id = data["groupId"]
 234        name = data["name"]
 235        created_at = data["creationDate"]
 236        member_count = data["memberCount"]
 237        about = data["about"]
 238        motto = data["motto"]
 239        is_public = data["isPublic"]
 240        banner = assets.Image(str(data["bannerPath"]))
 241        avatar = assets.Image(str(data["avatarPath"]))
 242        tags = data["tags"]
 243        type = data["groupType"]
 244
 245        features = data["features"]
 246        features_obj = clans.ClanFeatures(
 247            max_members=features["maximumMembers"],
 248            max_membership_types=features["maximumMembershipsOfGroupType"],
 249            capabilities=features["capabilities"],
 250            membership_types=features["membershipTypes"],
 251            invite_permissions=features["invitePermissionOverride"],
 252            update_banner_permissions=features["updateBannerPermissionOverride"],
 253            update_culture_permissions=features["updateCulturePermissionOverride"],
 254            join_level=features["joinLevel"],
 255        )
 256
 257        information: typedefs.JSONObject = data["clanInfo"]
 258        progression: collections.Mapping[int, progressions.Progression] = {
 259            int(prog_hash): self.deserialize_progressions(prog)
 260            for prog_hash, prog in information["d2ClanProgressions"].items()
 261        }
 262
 263        founder: typedefs.NoneOr[clans.ClanMember] = None
 264        if raw_founder := payload.get("founder"):
 265            founder = self.deserialize_clan_member(raw_founder)
 266
 267        return clans.Clan(
 268            net=self._net,
 269            id=int(id),
 270            name=name,
 271            type=enums.GroupType(type),
 272            created_at=time.clean_date(created_at),
 273            member_count=member_count,
 274            motto=motto,
 275            about=about,
 276            is_public=is_public,
 277            banner=banner,
 278            avatar=avatar,
 279            tags=tags,
 280            features=features_obj,
 281            owner=founder,
 282            progressions=progression,
 283            call_sign=information["clanCallsign"],
 284            banner_data=information["clanBannerData"],
 285            chat_security=data["chatSecurity"],
 286            conversation_id=int(data["conversationId"]),
 287            allow_chat=data["allowChat"],
 288            theme=data["theme"],
 289            current_user_membership=current_user_map,
 290        )
 291
 292    def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember:
 293        destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"])
 294        return clans.ClanMember(
 295            net=self._net,
 296            last_seen_name=destiny_user.last_seen_name,
 297            id=destiny_user.id,
 298            name=destiny_user.name,
 299            icon=destiny_user.icon,
 300            last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])),
 301            group_id=int(data["groupId"]),
 302            joined_at=time.clean_date(data["joinDate"]),
 303            types=destiny_user.types,
 304            is_public=destiny_user.is_public,
 305            type=destiny_user.type,
 306            code=destiny_user.code,
 307            is_online=data["isOnline"],
 308            crossave_override=destiny_user.crossave_override,
 309            bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"])
 310            if "bungieNetUserInfo" in data
 311            else None,
 312            member_type=enums.ClanMemberType(int(data["memberType"])),
 313        )
 314
 315    def deserialize_clan_members(
 316        self, data: typedefs.JSONObject, /
 317    ) -> iterators.Iterator[clans.ClanMember]:
 318        return iterators.Iterator(
 319            [self.deserialize_clan_member(member) for member in data["results"]]
 320        )
 321
 322    def deserialize_group_member(
 323        self, payload: typedefs.JSONObject
 324    ) -> clans.GroupMember:
 325        member = payload["member"]
 326        return clans.GroupMember(
 327            net=self._net,
 328            join_date=time.clean_date(member["joinDate"]),
 329            group_id=int(member["groupId"]),
 330            member_type=enums.ClanMemberType(member["memberType"]),
 331            is_online=member["isOnline"],
 332            last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])),
 333            inactive_memberships=payload.get("areAllMembershipsInactive", None),
 334            member=self.deserialize_destiny_membership(member["destinyUserInfo"]),
 335            group=self.deserialize_clan(payload["group"]),
 336        )
 337
 338    def _deserialize_clan_conversation(
 339        self, payload: typedefs.JSONObject
 340    ) -> clans.ClanConversation:
 341        return clans.ClanConversation(
 342            net=self._net,
 343            id=int(payload["conversationId"]),
 344            group_id=int(payload["groupId"]),
 345            name=(
 346                payload["chatName"]
 347                if not typedefs.is_unknown(payload["chatName"])
 348                else undefined.UNDEFINED
 349            ),
 350            chat_enabled=payload["chatEnabled"],
 351            security=payload["chatSecurity"],
 352        )
 353
 354    def deserialize_clan_conversations(
 355        self, payload: typedefs.JSONArray
 356    ) -> collections.Sequence[clans.ClanConversation]:
 357        return [self._deserialize_clan_conversation(conv) for conv in payload]
 358
 359    def deserialize_app_owner(
 360        self, payload: typedefs.JSONObject
 361    ) -> application.ApplicationOwner:
 362        return application.ApplicationOwner(
 363            net=self._net,
 364            name=payload.get("bungieGlobalDisplayName", undefined.UNDEFINED),
 365            id=int(payload["membershipId"]),
 366            type=enums.MembershipType(payload["membershipType"]),
 367            icon=assets.Image(str(payload["iconPath"])),
 368            is_public=payload["isPublic"],
 369            code=payload.get("bungieGlobalDisplayNameCode", None),
 370        )
 371
 372    def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application:
 373        return application.Application(
 374            id=int(payload["applicationId"]),
 375            name=payload["name"],
 376            link=payload["link"],
 377            status=payload["status"],
 378            redirect_url=payload.get("redirectUrl", None),
 379            created_at=time.clean_date(str(payload["creationDate"])),
 380            published_at=time.clean_date(str(payload["firstPublished"])),
 381            owner=self.deserialize_app_owner(payload["team"][0]["user"]),  # type: ignore
 382            scope=payload.get("scope", undefined.UNDEFINED),
 383        )
 384
 385    def _set_character_attrs(self, payload: typedefs.JSONObject) -> character.Character:
 386        total_time = time.format_played(int(payload["minutesPlayedTotal"]), suffix=True)
 387        return character.Character(
 388            net=self._net,
 389            id=int(payload["characterId"]),
 390            gender=enums.Gender(payload["genderType"]),
 391            race=enums.Race(payload["raceType"]),
 392            class_type=enums.Class(payload["classType"]),
 393            emblem=assets.Image(str(payload["emblemBackgroundPath"])),
 394            emblem_icon=assets.Image(str(payload["emblemPath"])),
 395            emblem_hash=int(payload["emblemHash"]),
 396            last_played=time.clean_date(payload["dateLastPlayed"]),
 397            total_played_time=total_time,
 398            member_id=int(payload["membershipId"]),
 399            member_type=enums.MembershipType(payload["membershipType"]),
 400            level=payload["baseCharacterLevel"],
 401            title_hash=payload.get("titleRecordHash", None),
 402            light=payload["light"],
 403            stats={enums.Stat(int(k)): v for k, v in payload["stats"].items()},
 404        )
 405
 406    def deserialize_profile(
 407        self, payload: typedefs.JSONObject, /
 408    ) -> typing.Optional[profile.Profile]:
 409        if (raw_profile := payload.get("data")) is None:
 410            return None
 411
 412        payload = raw_profile
 413        id = int(payload["userInfo"]["membershipId"])
 414        name = payload["userInfo"]["displayName"]
 415        is_public = payload["userInfo"]["isPublic"]
 416        type = enums.MembershipType(payload["userInfo"]["membershipType"])
 417        last_played = time.clean_date(str(payload["dateLastPlayed"]))
 418        character_ids = [int(cid) for cid in payload["characterIds"]]
 419        power_cap = payload["currentSeasonRewardPowerCap"]
 420
 421        return profile.Profile(
 422            id=int(id),
 423            name=name,
 424            is_public=is_public,
 425            type=type,
 426            last_played=last_played,
 427            character_ids=character_ids,
 428            power_cap=power_cap,
 429            net=self._net,
 430        )
 431
 432    def deserialize_profile_item(
 433        self, payload: typedefs.JSONObject
 434    ) -> profile.ProfileItemImpl:
 435
 436        instance_id: typing.Optional[int] = None
 437        if raw_instance_id := payload.get("itemInstanceId"):
 438            instance_id = int(raw_instance_id)
 439
 440        version_number: typing.Optional[int] = None
 441        if raw_version := payload.get("versionNumber"):
 442            version_number = int(raw_version)
 443
 444        transfer_status = enums.TransferStatus(payload["transferStatus"])
 445
 446        return profile.ProfileItemImpl(
 447            net=self._net,
 448            hash=payload["itemHash"],
 449            quantity=payload["quantity"],
 450            bind_status=enums.ItemBindStatus(payload["bindStatus"]),
 451            location=enums.ItemLocation(payload["location"]),
 452            bucket=payload["bucketHash"],
 453            transfer_status=transfer_status,
 454            lockable=payload["lockable"],
 455            state=enums.ItemState(payload["state"]),
 456            dismantel_permissions=payload["dismantlePermission"],
 457            is_wrapper=payload["isWrapper"],
 458            instance_id=instance_id,
 459            version_number=version_number,
 460            ornament_id=payload.get("overrideStyleItemHash"),
 461        )
 462
 463    def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective:
 464        return records.Objective(
 465            net=self._net,
 466            hash=payload["objectiveHash"],
 467            visible=payload["visible"],
 468            complete=payload["complete"],
 469            completion_value=payload["completionValue"],
 470            progress=payload.get("progress"),
 471            destination_hash=payload.get("destinationHash"),
 472            activity_hash=payload.get("activityHash"),
 473        )
 474
 475    def deserialize_records(
 476        self,
 477        payload: typedefs.JSONObject,
 478        scores: typing.Optional[records.RecordScores] = None,
 479        **nodes: int,
 480    ) -> records.Record:
 481        objectives: typing.Optional[list[records.Objective]] = None
 482        interval_objectives: typing.Optional[list[records.Objective]] = None
 483        record_state: typedefs.IntAnd[records.RecordState]
 484
 485        record_state = records.RecordState(payload["state"])
 486
 487        if raw_objs := payload.get("objectives"):
 488            objectives = [self.deserialize_objectives(obj) for obj in raw_objs]
 489
 490        if raw_interval_objs := payload.get("intervalObjectives"):
 491            interval_objectives = [
 492                self.deserialize_objectives(obj) for obj in raw_interval_objs
 493            ]
 494
 495        return records.Record(
 496            scores=scores,
 497            categories_node_hash=nodes.get("categories_hash", undefined.UNDEFINED),
 498            seals_node_hash=nodes.get("seals_hash", undefined.UNDEFINED),
 499            state=record_state,
 500            objectives=objectives,
 501            interval_objectives=interval_objectives,
 502            redeemed_count=payload.get("intervalsRedeemedCount", 0),
 503            completion_times=payload.get("completedCount", None),
 504            reward_visibility=payload.get("rewardVisibilty", None),
 505        )
 506
 507    def deserialize_character_records(
 508        self,
 509        payload: typedefs.JSONObject,
 510        scores: typing.Optional[records.RecordScores] = None,
 511        record_hashes: typing.Optional[list[int]] = None,
 512    ) -> records.CharacterRecord:
 513
 514        record = self.deserialize_records(payload, scores)
 515        return records.CharacterRecord(
 516            scores=scores,
 517            categories_node_hash=record.categories_node_hash,
 518            seals_node_hash=record.seals_node_hash,
 519            state=record.state,
 520            objectives=record.objectives,
 521            interval_objectives=record.interval_objectives,
 522            redeemed_count=payload.get("intervalsRedeemedCount", 0),
 523            completion_times=payload.get("completedCount"),
 524            reward_visibility=payload.get("rewardVisibilty"),
 525            record_hashes=record_hashes or [],
 526        )
 527
 528    def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye:
 529        return character.Dye(
 530            channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"]
 531        )
 532
 533    def deserialize_character_customization(
 534        self, payload: typedefs.JSONObject
 535    ) -> character.CustomizationOptions:
 536        return character.CustomizationOptions(
 537            personality=payload["personality"],
 538            face=payload["face"],
 539            skin_color=payload["skinColor"],
 540            lip_color=payload["lipColor"],
 541            eye_color=payload["eyeColor"],
 542            hair_colors=payload.get("hairColors", []),
 543            feature_colors=payload.get("featureColors", []),
 544            decal_color=payload["decalColor"],
 545            wear_helmet=payload["wearHelmet"],
 546            hair_index=payload["hairIndex"],
 547            feature_index=payload["featureIndex"],
 548            decal_index=payload["decalIndex"],
 549        )
 550
 551    def deserialize_character_minimal_equipments(
 552        self, payload: typedefs.JSONObject
 553    ) -> character.MinimalEquipments:
 554        dyes = None
 555        if raw_dyes := payload.get("dyes"):
 556            if raw_dyes:
 557                dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes]
 558        return character.MinimalEquipments(
 559            net=self._net, item_hash=payload["itemHash"], dyes=dyes
 560        )
 561
 562    def deserialize_character_render_data(
 563        self, payload: typedefs.JSONObject, /
 564    ) -> character.RenderedData:
 565        return character.RenderedData(
 566            net=self._net,
 567            customization=self.deserialize_character_customization(
 568                payload["customization"]
 569            ),
 570            custom_dyes=[
 571                self.deserialize_character_dye(dye)
 572                for dye in payload["customDyes"]
 573                if dye
 574            ],
 575            equipment=[
 576                self.deserialize_character_minimal_equipments(equipment)
 577                for equipment in payload["peerView"]["equipment"]
 578            ],
 579        )
 580
 581    def deserialize_available_activity(
 582        self, payload: typedefs.JSONObject
 583    ) -> activity.AvailableActivity:
 584        return activity.AvailableActivity(
 585            hash=payload["activityHash"],
 586            is_new=payload["isNew"],
 587            is_completed=payload["isCompleted"],
 588            is_visible=payload["isVisible"],
 589            display_level=payload.get("displayLevel"),
 590            recommended_light=payload.get("recommendedLight"),
 591            difficulty=activity.Difficulty(payload["difficultyTier"]),
 592            can_join=payload["canJoin"],
 593            can_lead=payload["canLead"],
 594        )
 595
 596    def deserialize_character_activity(
 597        self, payload: typedefs.JSONObject
 598    ) -> activity.CharacterActivity:
 599        current_mode: typing.Optional[enums.GameMode] = None
 600        if raw_current_mode := payload.get("currentActivityModeType"):
 601            current_mode = enums.GameMode(raw_current_mode)
 602
 603        current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None
 604        if raw_current_modes := payload.get("currentActivityModeTypes"):
 605            current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes]
 606
 607        return activity.CharacterActivity(
 608            date_started=time.clean_date(payload["dateActivityStarted"]),
 609            current_hash=payload["currentActivityHash"],
 610            current_mode_hash=payload["currentActivityModeHash"],
 611            current_mode=current_mode,
 612            current_mode_hashes=payload.get("currentActivityModeHashes"),
 613            current_mode_types=current_mode_types,
 614            current_playlist_hash=payload.get("currentPlaylistActivityHash"),
 615            last_story_hash=payload["lastCompletedStoryHash"],
 616            available_activities=[
 617                self.deserialize_available_activity(activity_)
 618                for activity_ in payload["availableActivities"]
 619            ],
 620        )
 621
 622    def deserialize_profile_items(
 623        self, payload: typedefs.JSONObject, /
 624    ) -> list[profile.ProfileItemImpl]:
 625        return [self.deserialize_profile_item(item) for item in payload["items"]]
 626
 627    def _deserialize_node(self, payload: typedefs.JSONObject) -> records.Node:
 628        return records.Node(
 629            state=int(payload["state"]),
 630            objective=self.deserialize_objectives(payload["objective"])
 631            if "objective" in payload
 632            else None,
 633            progress_value=int(payload["progressValue"]),
 634            completion_value=int(payload["completionValue"]),
 635            record_category_score=int(payload["recordCategoryScore"])
 636            if "recordCategoryScore" in payload
 637            else None,
 638        )
 639
 640    @staticmethod
 641    def _deserialize_collectible(payload: typedefs.JSONObject) -> items.Collectible:
 642        recent_collectibles: typing.Optional[collections.Collection[int]] = None
 643        if raw_recent_collectibles := payload.get("recentCollectibleHashes"):
 644            recent_collectibles = [
 645                int(item_hash) for item_hash in raw_recent_collectibles
 646            ]
 647
 648        collectibles: dict[int, int] = {}
 649        for item_hash, mapping in payload["collectibles"].items():
 650            collectibles[int(item_hash)] = int(mapping["state"])
 651
 652        return items.Collectible(
 653            recent_collectibles=recent_collectibles,
 654            collectibles=collectibles,
 655            collection_categorie_hash=int(payload["collectionCategoriesRootNodeHash"]),
 656            collection_badges_hash=int(payload["collectionBadgesRootNodeHash"]),
 657        )
 658
 659    @staticmethod
 660    def _deserialize_currencies(
 661        payload: typedefs.JSONObject,
 662    ) -> collections.Sequence[items.Currency]:
 663        return [
 664            items.Currency(hash=int(item_hash), amount=int(amount))
 665            for item_hash, amount in payload["itemQuantities"].items()
 666        ]
 667
 668    def deserialize_progressions(
 669        self, payload: typedefs.JSONObject
 670    ) -> progressions.Progression:
 671        return progressions.Progression(
 672            hash=int(payload["progressionHash"]),
 673            level=int(payload["level"]),
 674            cap=int(payload["levelCap"]),
 675            daily_limit=int(payload["dailyLimit"]),
 676            weekly_limit=int(payload["weeklyLimit"]),
 677            current_progress=int(payload["currentProgress"]),
 678            daily_progress=int(payload["dailyProgress"]),
 679            needed=int(payload["progressToNextLevel"]),
 680            next_level=int(payload["nextLevelAt"]),
 681        )
 682
 683    def _deserialize_factions(
 684        self, payload: typedefs.JSONObject
 685    ) -> progressions.Factions:
 686        progs = self.deserialize_progressions(payload)
 687        return progressions.Factions(
 688            hash=progs.hash,
 689            level=progs.level,
 690            cap=progs.cap,
 691            daily_limit=progs.daily_limit,
 692            weekly_limit=progs.weekly_limit,
 693            current_progress=progs.current_progress,
 694            daily_progress=progs.daily_progress,
 695            needed=progs.needed,
 696            next_level=progs.next_level,
 697            faction_hash=payload["factionHash"],
 698            faction_vendor_hash=payload["factionVendorIndex"],
 699        )
 700
 701    def _deserialize_milestone_available_quest(
 702        self, payload: typedefs.JSONObject
 703    ) -> milestones.MilestoneQuest:
 704        return milestones.MilestoneQuest(
 705            item_hash=payload["questItemHash"],
 706            status=self._deserialize_milestone_quest_status(payload["status"]),
 707        )
 708
 709    def _deserialize_milestone_activity(
 710        self, payload: typedefs.JSONObject
 711    ) -> milestones.MilestoneActivity:
 712
 713        phases: typing.Optional[
 714            collections.Sequence[milestones.MilestoneActivityPhase]
 715        ] = None
 716        if raw_phases := payload.get("phases"):
 717            phases = [
 718                milestones.MilestoneActivityPhase(
 719                    is_completed=obj["complete"], hash=obj["phaseHash"]
 720                )
 721                for obj in raw_phases
 722            ]
 723
 724        return milestones.MilestoneActivity(
 725            hash=payload["activityHash"],
 726            challenges=[
 727                self.deserialize_objectives(obj["objective"])
 728                for obj in payload["challenges"]
 729            ],
 730            modifier_hashes=payload.get("modifierHashes"),
 731            boolean_options=payload.get("booleanActivityOptions"),
 732            phases=phases,
 733        )
 734
 735    def _deserialize_milestone_quest_status(
 736        self, payload: typedefs.JSONObject
 737    ) -> milestones.QuestStatus:
 738        return milestones.QuestStatus(
 739            net=self._net,
 740            quest_hash=payload["questHash"],
 741            step_hash=payload["stepHash"],
 742            step_objectives=[
 743                self.deserialize_objectives(objective)
 744                for objective in payload["stepObjectives"]
 745            ],
 746            is_tracked=payload["tracked"],
 747            is_completed=payload["completed"],
 748            started=payload["started"],
 749            item_instance_id=payload["itemInstanceId"],
 750            vendor_hash=payload.get("vendorHash"),
 751            is_redeemed=payload["redeemed"],
 752        )
 753
 754    def _deserialize_milestone_rewards(
 755        self, payload: typedefs.JSONObject
 756    ) -> milestones.MilestoneReward:
 757        return milestones.MilestoneReward(
 758            category_hash=payload["rewardCategoryHash"],
 759            entries=[
 760                milestones.MilestoneRewardEntry(
 761                    entry_hash=entry["rewardEntryHash"],
 762                    is_earned=entry["earned"],
 763                    is_redeemed=entry["redeemed"],
 764                )
 765                for entry in payload["entries"]
 766            ],
 767        )
 768
 769    def deserialize_milestone(
 770        self, payload: typedefs.JSONObject
 771    ) -> milestones.Milestone:
 772        start_date: typing.Optional[datetime.datetime] = None
 773        if raw_start_date := payload.get("startDate"):
 774            start_date = time.clean_date(raw_start_date)
 775
 776        end_date: typing.Optional[datetime.datetime] = None
 777        if raw_end_date := payload.get("endDate"):
 778            end_date = time.clean_date(raw_end_date)
 779
 780        rewards: typing.Optional[
 781            collections.Collection[milestones.MilestoneReward]
 782        ] = None
 783        if raw_rewards := payload.get("rewards"):
 784            rewards = [
 785                self._deserialize_milestone_rewards(reward) for reward in raw_rewards
 786            ]
 787
 788        activities: typing.Optional[
 789            collections.Sequence[milestones.MilestoneActivity]
 790        ] = None
 791        if raw_activities := payload.get("activities"):
 792            activities = [
 793                self._deserialize_milestone_activity(active)
 794                for active in raw_activities
 795            ]
 796
 797        quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None
 798        if raw_quests := payload.get("availableQuests"):
 799            quests = [
 800                self._deserialize_milestone_available_quest(quest)
 801                for quest in raw_quests
 802            ]
 803
 804        vendors: typing.Optional[
 805            collections.Sequence[milestones.MilestoneVendor]
 806        ] = None
 807        if raw_vendors := payload.get("vendors"):
 808            vendors = [
 809                milestones.MilestoneVendor(
 810                    vendor_hash=vendor["vendorHash"],
 811                    preview_itemhash=vendor.get("previewItemHash"),
 812                )
 813                for vendor in raw_vendors
 814            ]
 815
 816        return milestones.Milestone(
 817            hash=payload["milestoneHash"],
 818            start_date=start_date,
 819            end_date=end_date,
 820            order=payload["order"],
 821            rewards=rewards,
 822            available_quests=quests,
 823            activities=activities,
 824            vendors=vendors,
 825        )
 826
 827    def _deserialize_artifact_tiers(
 828        self, payload: typedefs.JSONObject
 829    ) -> season.ArtifactTier:
 830        return season.ArtifactTier(
 831            hash=payload["tierHash"],
 832            is_unlocked=payload["isUnlocked"],
 833            points_to_unlock=payload["pointsToUnlock"],
 834            items=[
 835                season.ArtifactTierItem(
 836                    hash=item["itemHash"], is_active=item["isActive"]
 837                )
 838                for item in payload["items"]
 839            ],
 840        )
 841
 842    def deserialize_characters(
 843        self, payload: typedefs.JSONObject
 844    ) -> collections.Mapping[int, character.Character]:
 845        return {
 846            int(char_id): self._set_character_attrs(char)
 847            for char_id, char in payload["data"].items()
 848        }
 849
 850    def deserialize_character(
 851        self, payload: typedefs.JSONObject
 852    ) -> character.Character:
 853        return self._set_character_attrs(payload)
 854
 855    def deserialize_character_equipments(
 856        self, payload: typedefs.JSONObject
 857    ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]:
 858        return {
 859            int(char_id): self.deserialize_profile_items(item)
 860            for char_id, item in payload["data"].items()
 861        }
 862
 863    def deserialize_character_activities(
 864        self, payload: typedefs.JSONObject
 865    ) -> collections.Mapping[int, activity.CharacterActivity]:
 866        return {
 867            int(char_id): self.deserialize_character_activity(data)
 868            for char_id, data in payload["data"].items()
 869        }
 870
 871    def deserialize_characters_render_data(
 872        self, payload: typedefs.JSONObject
 873    ) -> collections.Mapping[int, character.RenderedData]:
 874        return {
 875            int(char_id): self.deserialize_character_render_data(data)
 876            for char_id, data in payload["data"].items()
 877        }
 878
 879    def deserialize_character_progressions(
 880        self, payload: typedefs.JSONObject
 881    ) -> character.CharacterProgression:
 882        progressions_ = {
 883            int(prog_id): self.deserialize_progressions(prog)
 884            for prog_id, prog in payload["progressions"].items()
 885        }
 886
 887        factions = {
 888            int(faction_id): self._deserialize_factions(faction)
 889            for faction_id, faction in payload["factions"].items()
 890        }
 891
 892        milestones_ = {
 893            int(milestone_hash): self.deserialize_milestone(milestone)
 894            for milestone_hash, milestone in payload["milestones"].items()
 895        }
 896
 897        uninstanced_item_objectives = {
 898            int(item_hash): [self.deserialize_objectives(ins) for ins in obj]
 899            for item_hash, obj in payload["uninstancedItemObjectives"].items()
 900        }
 901
 902        artifact = payload["seasonalArtifact"]
 903        seasonal_artifact = season.CharacterScopedArtifact(
 904            hash=artifact["artifactHash"],
 905            points_used=artifact["pointsUsed"],
 906            reset_count=artifact["resetCount"],
 907            tiers=[
 908                self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"]
 909            ],
 910        )
 911        checklists = payload["checklists"]
 912
 913        return character.CharacterProgression(
 914            progressions=progressions_,
 915            factions=factions,
 916            checklists=checklists,
 917            milestones=milestones_,
 918            seasonal_artifact=seasonal_artifact,
 919            uninstanced_item_objectives=uninstanced_item_objectives,
 920        )
 921
 922    def deserialize_character_progressions_mapping(
 923        self, payload: typedefs.JSONObject
 924    ) -> collections.Mapping[int, character.CharacterProgression]:
 925        character_progressions: collections.Mapping[
 926            int, character.CharacterProgression
 927        ] = {}
 928        for char_id, data in payload["data"].items():
 929            # A little hack to stop mypy complaining about Mapping <-> dict
 930            character_progressions[int(char_id)] = self.deserialize_character_progressions(data)  # type: ignore[index]
 931        return character_progressions
 932
 933    def deserialize_characters_records(
 934        self,
 935        payload: typedefs.JSONObject,
 936    ) -> collections.Mapping[int, records.CharacterRecord]:
 937
 938        return {
 939            int(rec_id): self.deserialize_character_records(
 940                rec, record_hashes=payload.get("featuredRecordHashes")
 941            )
 942            for rec_id, rec in payload["records"].items()
 943        }
 944
 945    def deserialize_profile_records(
 946        self, payload: typedefs.JSONObject
 947    ) -> collections.Mapping[int, records.Record]:
 948        raw_profile_records = payload["data"]
 949        scores = records.RecordScores(
 950            current_score=raw_profile_records["score"],
 951            legacy_score=raw_profile_records["legacyScore"],
 952            lifetime_score=raw_profile_records["lifetimeScore"],
 953        )
 954        return {
 955            int(record_id): self.deserialize_records(
 956                record,
 957                scores,
 958                categories_hash=raw_profile_records["recordCategoriesRootNodeHash"],
 959                seals_hash=raw_profile_records["recordSealsRootNodeHash"],
 960            )
 961            for record_id, record in raw_profile_records["records"].items()
 962        }
 963
 964    def _deserialize_craftable_socket_plug(
 965        self, payload: typedefs.JSONObject
 966    ) -> items.CraftableSocketPlug:
 967        return items.CraftableSocketPlug(
 968            item_hash=int(payload["plugItemHash"]),
 969            failed_requirement_indexes=payload.get("failedRequirementIndexes", []),
 970        )
 971
 972    def _deserialize_craftable_socket(
 973        self, payload: typedefs.JSONObject
 974    ) -> items.CraftableSocket:
 975
 976        plugs: list[items.CraftableSocketPlug] = []
 977        if raw_plug := payload.get("plug"):
 978            plugs.extend(
 979                self._deserialize_craftable_socket_plug(plug) for plug in raw_plug
 980            )
 981
 982        return items.CraftableSocket(
 983            plug_set_hash=int(payload["plugSetHash"]), plugs=plugs
 984        )
 985
 986    def _deserialize_craftable_item(
 987        self, payload: typedefs.JSONObject
 988    ) -> items.CraftableItem:
 989
 990        return items.CraftableItem(
 991            is_visible=payload["visible"],
 992            failed_requirement_indexes=payload.get("failedRequirementIndexes", []),
 993            sockets=[
 994                self._deserialize_craftable_socket(socket)
 995                for socket in payload["sockets"]
 996            ],
 997        )
 998
 999    def deserialize_craftables_component(
1000        self, payload: typedefs.JSONObject
1001    ) -> components.CraftablesComponent:
1002        return components.CraftablesComponent(
1003            net=self._net,
1004            craftables={
1005                int(item_id): self._deserialize_craftable_item(item)
1006                for item_id, item in payload["craftables"].items()
1007                if item is not None
1008            },
1009            crafting_root_node_hash=payload["craftingRootNodeHash"],
1010        )
1011
1012    def deserialize_components(  # noqa: C901 Too complex.
1013        self, payload: typedefs.JSONObject
1014    ) -> components.Component:
1015
1016        profile_: typing.Optional[profile.Profile] = None
1017        if raw_profile := payload.get("profile"):
1018            profile_ = self.deserialize_profile(raw_profile)
1019
1020        profile_progression: typing.Optional[profile.ProfileProgression] = None
1021        if raw_profile_progression := payload.get("profileProgression"):
1022            profile_progression = self.deserialize_profile_progression(
1023                raw_profile_progression
1024            )
1025
1026        profile_currencies: typing.Optional[
1027            collections.Sequence[profile.ProfileItemImpl]
1028        ] = None
1029        if raw_profile_currencies := payload.get("profileCurrencies"):
1030            if "data" in raw_profile_currencies:
1031                profile_currencies = self.deserialize_profile_items(
1032                    raw_profile_currencies["data"]
1033                )
1034
1035        profile_inventories: typing.Optional[
1036            collections.Sequence[profile.ProfileItemImpl]
1037        ] = None
1038        if raw_profile_inventories := payload.get("profileInventory"):
1039            if "data" in raw_profile_inventories:
1040                profile_inventories = self.deserialize_profile_items(
1041                    raw_profile_inventories["data"]
1042                )
1043
1044        profile_records: typing.Optional[
1045            collections.Mapping[int, records.Record]
1046        ] = None
1047
1048        if raw_profile_records_ := payload.get("profileRecords"):
1049            profile_records = self.deserialize_profile_records(raw_profile_records_)
1050
1051        characters: typing.Optional[typing.Mapping[int, character.Character]] = None
1052        if raw_characters := payload.get("characters"):
1053            characters = self.deserialize_characters(raw_characters)
1054
1055        character_records: typing.Optional[
1056            collections.Mapping[int, records.CharacterRecord]
1057        ] = None
1058
1059        if raw_character_records := payload.get("characterRecords"):
1060            # Had to do it in two steps..
1061            to_update: typedefs.JSONObject = {}
1062            for _, data in raw_character_records["data"].items():
1063                for record_id, record in data.items():
1064                    to_update[record_id] = record
1065
1066            character_records = {
1067                int(rec_id): self.deserialize_character_records(
1068                    rec, record_hashes=to_update.get("featuredRecordHashes")
1069                )
1070                for rec_id, rec in to_update["records"].items()
1071            }
1072
1073        character_equipments: typing.Optional[
1074            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1075        ] = None
1076        if raw_character_equips := payload.get("characterEquipment"):
1077            character_equipments = self.deserialize_character_equipments(
1078                raw_character_equips
1079            )
1080
1081        character_inventories: typing.Optional[
1082            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1083        ] = None
1084        if raw_character_inventories := payload.get("characterInventories"):
1085            if "data" in raw_character_inventories:
1086                character_inventories = self.deserialize_character_equipments(
1087                    raw_character_inventories
1088                )
1089
1090        character_activities: typing.Optional[
1091            collections.Mapping[int, activity.CharacterActivity]
1092        ] = None
1093        if raw_char_acts := payload.get("characterActivities"):
1094            character_activities = self.deserialize_character_activities(raw_char_acts)
1095
1096        character_render_data: typing.Optional[
1097            collections.Mapping[int, character.RenderedData]
1098        ] = None
1099        if raw_character_render_data := payload.get("characterRenderData"):
1100            character_render_data = self.deserialize_characters_render_data(
1101                raw_character_render_data
1102            )
1103
1104        character_progressions: typing.Optional[
1105            collections.Mapping[int, character.CharacterProgression]
1106        ] = None
1107
1108        if raw_character_progressions := payload.get("characterProgressions"):
1109            character_progressions = self.deserialize_character_progressions_mapping(
1110                raw_character_progressions
1111            )
1112
1113        profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None
1114        if raw_profile_string_vars := payload.get("profileStringVariables"):
1115            profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"]
1116
1117        character_string_vars: typing.Optional[
1118            collections.Mapping[int, collections.Mapping[int, int]]
1119        ] = None
1120        if raw_character_string_vars := payload.get("characterStringVariables"):
1121            character_string_vars = {
1122                int(char_id): data["integerValuesByHash"]
1123                for char_id, data in raw_character_string_vars["data"].items()
1124            }
1125
1126        metrics: typing.Optional[
1127            collections.Sequence[
1128                collections.Mapping[
1129                    int, tuple[bool, typing.Optional[records.Objective]]
1130                ]
1131            ]
1132        ] = None
1133        root_node_hash: typing.Optional[int] = None
1134
1135        if raw_metrics := payload.get("metrics"):
1136            root_node_hash = raw_metrics["data"]["metricsRootNodeHash"]
1137            metrics = [
1138                {
1139                    int(metrics_hash): (
1140                        data["invisible"],
1141                        self.deserialize_objectives(data["objectiveProgress"])
1142                        if "objectiveProgress" in data
1143                        else None,
1144                    )
1145                    for metrics_hash, data in raw_metrics["data"]["metrics"].items()
1146                }
1147            ]
1148        transitory: typing.Optional[fireteams.FireteamParty] = None
1149        if raw_transitory := payload.get("profileTransitoryData"):
1150            if "data" in raw_transitory:
1151                transitory = self.deserialize_fireteam_party(raw_transitory["data"])
1152
1153        item_components: typing.Optional[components.ItemsComponent] = None
1154        if raw_item_components := payload.get("itemComponents"):
1155            item_components = self.deserialize_items_component(raw_item_components)
1156
1157        profile_plugsets: typing.Optional[
1158            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1159        ] = None
1160
1161        if raw_profile_plugs := payload.get("profilePlugSets"):
1162            profile_plugsets = {
1163                int(index): [self.deserialize_plug_item_state(state) for state in data]
1164                for index, data in raw_profile_plugs["data"]["plugs"].items()
1165            }
1166
1167        character_plugsets: typing.Optional[
1168            collections.Mapping[
1169                int, collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1170            ]
1171        ] = None
1172        if raw_char_plugsets := payload.get("characterPlugSets"):
1173            character_plugsets = {
1174                int(char_id): {
1175                    int(index): [
1176                        self.deserialize_plug_item_state(state) for state in data
1177                    ]
1178                    for index, data in inner["plugs"].items()
1179                }
1180                for char_id, inner in raw_char_plugsets["data"].items()
1181            }
1182
1183        character_collectibles: typing.Optional[
1184            collections.Mapping[int, items.Collectible]
1185        ] = None
1186        if raw_character_collectibles := payload.get("characterCollectibles"):
1187            character_collectibles = {
1188                int(char_id): self._deserialize_collectible(data)
1189                for char_id, data in raw_character_collectibles["data"].items()
1190            }
1191
1192        profile_collectibles: typing.Optional[items.Collectible] = None
1193        if raw_profile_collectibles := payload.get("profileCollectibles"):
1194            profile_collectibles = self._deserialize_collectible(
1195                raw_profile_collectibles["data"]
1196            )
1197
1198        profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1199        if raw_profile_nodes := payload.get("profilePresentationNodes"):
1200            profile_nodes = {
1201                int(node_hash): self._deserialize_node(node)
1202                for node_hash, node in raw_profile_nodes["data"]["nodes"].items()
1203            }
1204
1205        character_nodes: typing.Optional[
1206            collections.Mapping[int, collections.Mapping[int, records.Node]]
1207        ] = None
1208        if raw_character_nodes := payload.get("characterPresentationNodes"):
1209            character_nodes = {
1210                int(char_id): {
1211                    int(node_hash): self._deserialize_node(node)
1212                    for node_hash, node in each_character["nodes"].items()
1213                }
1214                for char_id, each_character in raw_character_nodes["data"].items()
1215            }
1216
1217        platform_silver: typing.Optional[
1218            collections.Mapping[str, profile.ProfileItemImpl]
1219        ] = None
1220        if raw_platform_silver := payload.get("platformSilver"):
1221            if "data" in raw_platform_silver:
1222                platform_silver = {
1223                    platform_name: self.deserialize_profile_item(item)
1224                    for platform_name, item in raw_platform_silver["data"][
1225                        "platformSilver"
1226                    ].items()
1227                }
1228
1229        character_currency_lookups: typing.Optional[
1230            collections.Mapping[int, collections.Sequence[items.Currency]]
1231        ] = None
1232        if raw_char_lookups := payload.get("characterCurrencyLookups"):
1233            if "data" in raw_char_lookups:
1234                character_currency_lookups = {
1235                    int(char_id): self._deserialize_currencies(currencie)
1236                    for char_id, currencie in raw_char_lookups["data"].items()
1237                }
1238
1239        character_craftables: typing.Optional[
1240            collections.Mapping[int, components.CraftablesComponent]
1241        ] = None
1242        if raw_character_craftables := payload.get("characterCraftables"):
1243
1244            if "data" in raw_character_craftables:
1245                character_craftables = {
1246                    int(char_id): self.deserialize_craftables_component(craftable)
1247                    for char_id, craftable in raw_character_craftables["data"].items()
1248                }
1249
1250        return components.Component(
1251            profiles=profile_,
1252            profile_progression=profile_progression,
1253            profile_currencies=profile_currencies,
1254            profile_inventories=profile_inventories,
1255            profile_records=profile_records,
1256            characters=characters,
1257            character_records=character_records,
1258            character_equipments=character_equipments,
1259            character_inventories=character_inventories,
1260            character_activities=character_activities,
1261            character_render_data=character_render_data,
1262            character_progressions=character_progressions,
1263            profile_string_variables=profile_string_vars,
1264            character_string_variables=character_string_vars,
1265            metrics=metrics,
1266            root_node_hash=root_node_hash,
1267            transitory=transitory,
1268            item_components=item_components,
1269            profile_plugsets=profile_plugsets,
1270            character_plugsets=character_plugsets,
1271            character_collectibles=character_collectibles,
1272            profile_collectibles=profile_collectibles,
1273            profile_nodes=profile_nodes,
1274            character_nodes=character_nodes,
1275            platform_silver=platform_silver,
1276            character_currency_lookups=character_currency_lookups,
1277            character_craftables=character_craftables,
1278        )
1279
1280    def deserialize_items_component(
1281        self, payload: typedefs.JSONObject
1282    ) -> components.ItemsComponent:
1283        instances: typing.Optional[
1284            collections.Sequence[collections.Mapping[int, items.ItemInstance]]
1285        ] = None
1286        if raw_instances := payload.get("instances"):
1287            instances = [
1288                {
1289                    int(ins_id): self.deserialize_instanced_item(item)
1290                    for ins_id, item in raw_instances["data"].items()
1291                }
1292            ]
1293
1294        render_data: typing.Optional[
1295            collections.Mapping[int, tuple[bool, dict[int, int]]]
1296        ] = None
1297        if raw_render_data := payload.get("renderData"):
1298            render_data = {
1299                int(ins_id): (data["useCustomDyes"], data["artRegions"])
1300                for ins_id, data in raw_render_data["data"].items()
1301            }
1302
1303        stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None
1304        if raw_stats := payload.get("stats"):
1305            builder: collections.Mapping[int, items.ItemStatsView] = {}
1306            for ins_id, stat in raw_stats["data"].items():
1307                for _, items_ in stat.items():
1308                    builder[int(ins_id)] = self.deserialize_item_stats_view(items_)  # type: ignore[index]
1309            stats = builder
1310
1311        sockets: typing.Optional[
1312            collections.Mapping[int, collections.Sequence[items.ItemSocket]]
1313        ] = None
1314        if raw_sockets := payload.get("sockets"):
1315            sockets = {
1316                int(ins_id): [
1317                    self.deserialize_item_socket(socket) for socket in item["sockets"]
1318                ]
1319                for ins_id, item in raw_sockets["data"].items()
1320            }
1321
1322        objeectives: typing.Optional[
1323            collections.Mapping[int, collections.Sequence[records.Objective]]
1324        ] = None
1325        if raw_objectives := payload.get("objectives"):
1326            objeectives = {
1327                int(ins_id): [self.deserialize_objectives(objective)]
1328                for ins_id, data in raw_objectives["data"].items()
1329                for objective in data["objectives"]
1330            }
1331
1332        perks: typing.Optional[
1333            collections.Mapping[int, collections.Collection[items.ItemPerk]]
1334        ] = None
1335        if raw_perks := payload.get("perks"):
1336            perks = {
1337                int(ins_id): [
1338                    self.deserialize_item_perk(perk) for perk in item["perks"]
1339                ]
1340                for ins_id, item in raw_perks["data"].items()
1341            }
1342
1343        plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None
1344        if raw_plug_states := payload.get("plugStates"):
1345            pending_states: list[items.PlugItemState] = []
1346            for _, plug in raw_plug_states["data"].items():
1347                pending_states.append(self.deserialize_plug_item_state(plug))
1348            plug_states = pending_states
1349
1350        reusable_plugs: typing.Optional[
1351            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1352        ] = None
1353        if raw_re_plugs := payload.get("reusablePlugs"):
1354            reusable_plugs = {
1355                int(ins_id): [
1356                    self.deserialize_plug_item_state(state) for state in inner
1357                ]
1358                for ins_id, plug in raw_re_plugs["data"].items()
1359                for inner in list(plug["plugs"].values())
1360            }
1361
1362        plug_objectives: typing.Optional[
1363            collections.Mapping[
1364                int, collections.Mapping[int, collections.Collection[records.Objective]]
1365            ]
1366        ] = None
1367        if raw_plug_objectives := payload.get("plugObjectives"):
1368            plug_objectives = {
1369                int(ins_id): {
1370                    int(obj_hash): [self.deserialize_objectives(obj) for obj in objs]
1371                    for obj_hash, objs in inner["objectivesPerPlug"].items()
1372                }
1373                for ins_id, inner in raw_plug_objectives["data"].items()
1374            }
1375
1376        return components.ItemsComponent(
1377            sockets=sockets,
1378            stats=stats,
1379            render_data=render_data,
1380            instances=instances,
1381            objectives=objeectives,
1382            perks=perks,
1383            plug_states=plug_states,
1384            reusable_plugs=reusable_plugs,
1385            plug_objectives=plug_objectives,
1386        )
1387
1388    def deserialize_character_component(  # type: ignore[call-arg]
1389        self, payload: typedefs.JSONObject
1390    ) -> components.CharacterComponent:
1391
1392        character_: typing.Optional[character.Character] = None
1393        if raw_singuler_character := payload.get("character"):
1394            character_ = self.deserialize_character(raw_singuler_character["data"])
1395
1396        inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1397        if raw_inventory := payload.get("inventory"):
1398            if "data" in raw_inventory:
1399                inventory = self.deserialize_profile_items(raw_inventory["data"])
1400
1401        activities: typing.Optional[activity.CharacterActivity] = None
1402        if raw_activities := payload.get("activities"):
1403            activities = self.deserialize_character_activity(raw_activities["data"])
1404
1405        equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1406        if raw_equipments := payload.get("equipment"):
1407            equipment = self.deserialize_profile_items(raw_equipments["data"])
1408
1409        progressions_: typing.Optional[character.CharacterProgression] = None
1410        if raw_progressions := payload.get("progressions"):
1411            progressions_ = self.deserialize_character_progressions(
1412                raw_progressions["data"]
1413            )
1414
1415        render_data: typing.Optional[character.RenderedData] = None
1416        if raw_render_data := payload.get("renderData"):
1417            render_data = self.deserialize_character_render_data(
1418                raw_render_data["data"]
1419            )
1420
1421        character_records: typing.Optional[
1422            collections.Mapping[int, records.CharacterRecord]
1423        ] = None
1424        if raw_char_records := payload.get("records"):
1425            character_records = self.deserialize_characters_records(
1426                raw_char_records["data"]
1427            )
1428
1429        item_components: typing.Optional[components.ItemsComponent] = None
1430        if raw_item_components := payload.get("itemComponents"):
1431            item_components = self.deserialize_items_component(raw_item_components)
1432
1433        nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1434        if raw_nodes := payload.get("presentationNodes"):
1435            nodes = {
1436                int(node_hash): self._deserialize_node(node)
1437                for node_hash, node in raw_nodes["data"]["nodes"].items()
1438            }
1439
1440        collectibles: typing.Optional[items.Collectible] = None
1441        if raw_collectibles := payload.get("collectibles"):
1442            collectibles = self._deserialize_collectible(raw_collectibles["data"])
1443
1444        currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None
1445        if raw_currencies := payload.get("currencyLookups"):
1446            if "data" in raw_currencies:
1447                currency_lookups = self._deserialize_currencies(raw_currencies)
1448
1449        return components.CharacterComponent(
1450            activities=activities,
1451            equipment=equipment,
1452            inventory=inventory,
1453            progressions=progressions_,
1454            render_data=render_data,
1455            character=character_,
1456            character_records=character_records,
1457            profile_records=None,
1458            item_components=item_components,
1459            currency_lookups=currency_lookups,
1460            collectibles=collectibles,
1461            nodes=nodes,
1462        )
1463
1464    def _set_entity_attrs(
1465        self, payload: typedefs.JSONObject, *, key: str = "displayProperties"
1466    ) -> entity.Entity:
1467
1468        name: undefined.UndefinedOr[str] = undefined.UNDEFINED
1469        description: undefined.UndefinedOr[str] = undefined.UNDEFINED
1470
1471        if properties := payload[key]:
1472            if (raw_name := properties["name"]) is not typedefs.Unknown:
1473                name = raw_name
1474
1475            if (
1476                raw_description := properties["description"]
1477            ) and not typedefs.is_unknown(raw_description):
1478                description = raw_description
1479
1480        return entity.Entity(
1481            net=self._net,
1482            hash=payload["hash"],
1483            index=payload["index"],
1484            name=name,
1485            description=description,
1486            has_icon=properties["hasIcon"],
1487            icon=assets.Image(properties["icon"] if "icon" in properties else None),
1488        )
1489
1490    def deserialize_inventory_results(
1491        self, payload: typedefs.JSONObject
1492    ) -> iterators.Iterator[entity.SearchableEntity]:
1493        suggested_words: list[str] = payload["suggestedWords"]
1494
1495        def _check_unknown(s: str) -> undefined.UndefinedOr[str]:
1496            return s if not typedefs.is_unknown(s) else undefined.UNDEFINED
1497
1498        return iterators.Iterator(
1499            [
1500                entity.SearchableEntity(
1501                    net=self._net,
1502                    hash=data["hash"],
1503                    entity_type=data["entityType"],
1504                    weight=data["weight"],
1505                    suggested_words=suggested_words,
1506                    name=data["displayProperties"]["name"],
1507                    has_icon=data["displayProperties"]["hasIcon"],
1508                    description=_check_unknown(
1509                        data["displayProperties"]["description"]
1510                    ),
1511                    icon=assets.Image(data["displayProperties"]["icon"]),
1512                )
1513                for data in payload["results"]["results"]
1514            ]
1515        )
1516
1517    def _deserialize_inventory_item_objects(
1518        self, payload: typedefs.JSONObject
1519    ) -> entity.InventoryEntityObjects:
1520        return entity.InventoryEntityObjects(
1521            action=payload.get("action"),
1522            set_data=payload.get("setData"),
1523            stats=payload.get("stats"),
1524            equipping_block=payload.get("equippingBlock"),
1525            translation_block=payload.get("translationBlock"),
1526            preview=payload.get("preview"),
1527            quality=payload.get("quality"),
1528            value=payload.get("value"),
1529            source_data=payload.get("sourceData"),
1530            objectives=payload.get("objectives"),
1531            plug=payload.get("plug"),
1532            metrics=payload.get("metrics"),
1533            gearset=payload.get("gearset"),
1534            sack=payload.get("sack"),
1535            sockets=payload.get("sockets"),
1536            summary=payload.get("summary"),
1537            talent_gird=payload.get("talentGrid"),
1538            investments_stats=payload.get("investmentStats"),
1539            perks=payload.get("perks"),
1540            animations=payload.get("animations", []),
1541            links=payload.get("links", []),
1542        )
1543
1544    def deserialize_inventory_entity(  # noqa: C901 Too complex.
1545        self, payload: typedefs.JSONObject, /
1546    ) -> entity.InventoryEntity:
1547
1548        props = self._set_entity_attrs(payload)
1549        objects = self._deserialize_inventory_item_objects(payload)
1550
1551        collectible_hash: typing.Optional[int] = None
1552        if raw_collectible_hash := payload.get("collectibleHash"):
1553            collectible_hash = int(raw_collectible_hash)
1554
1555        secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1556        if raw_second_icon := payload.get("secondaryIcon"):
1557            secondary_icon = assets.Image(raw_second_icon)
1558
1559        secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1560        if raw_second_overlay := payload.get("secondaryOverlay"):
1561            secondary_overlay = assets.Image(raw_second_overlay)
1562
1563        secondary_special: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1564        if raw_second_special := payload.get("secondarySpecial"):
1565            secondary_special = assets.Image(raw_second_special)
1566
1567        screenshot: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1568        if raw_screenshot := payload.get("screenshot"):
1569            screenshot = assets.Image(raw_screenshot)
1570
1571        watermark_icon: typing.Optional[assets.Image] = None
1572        if raw_watermark_icon := payload.get("iconWatermark"):
1573            watermark_icon = assets.Image(raw_watermark_icon)
1574
1575        watermark_shelved: typing.Optional[assets.Image] = None
1576        if raw_watermark_shelved := payload.get("iconWatermarkShelved"):
1577            watermark_shelved = assets.Image(raw_watermark_shelved)
1578
1579        about: undefined.UndefinedOr[str] = undefined.UNDEFINED
1580        if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown(
1581            raw_about
1582        ):
1583            about = raw_about
1584
1585        ui_item_style: undefined.UndefinedOr[str] = undefined.UNDEFINED
1586        if (
1587            raw_ui_style := payload.get("uiItemDisplayStyle")
1588        ) and not typedefs.is_unknown(raw_ui_style):
1589            ui_item_style = raw_ui_style
1590
1591        tier_and_name: undefined.UndefinedOr[str] = undefined.UNDEFINED
1592        if (
1593            raw_tier_and_name := payload.get("itemTypeAndTierDisplayName")
1594        ) and not typedefs.is_unknown(raw_tier_and_name):
1595            tier_and_name = raw_tier_and_name
1596
1597        type_name: undefined.UndefinedOr[str] = undefined.UNDEFINED
1598        if (
1599            raw_type_name := payload.get("itemTypeDisplayName")
1600        ) and not typedefs.is_unknown(raw_type_name):
1601            type_name = raw_type_name
1602
1603        display_source: undefined.UndefinedOr[str] = undefined.UNDEFINED
1604        if (
1605            raw_display_source := payload.get("displaySource")
1606        ) and not typedefs.is_unknown(raw_display_source):
1607            display_source = raw_display_source
1608
1609        lorehash: typing.Optional[int] = None
1610        if raw_lore_hash := payload.get("loreHash"):
1611            lorehash = int(raw_lore_hash)
1612
1613        summary_hash: typing.Optional[int] = None
1614        if raw_summary_hash := payload.get("summaryItemHash"):
1615            summary_hash = raw_summary_hash
1616
1617        breaker_type_hash: typing.Optional[int] = None
1618        if raw_breaker_type_hash := payload.get("breakerTypeHash"):
1619            breaker_type_hash = int(raw_breaker_type_hash)
1620
1621        damage_types: typing.Optional[collections.Sequence[int]] = None
1622        if raw_damage_types := payload.get("damageTypes"):
1623            damage_types = [int(type_) for type_ in raw_damage_types]
1624
1625        damagetype_hashes: typing.Optional[collections.Sequence[int]] = None
1626        if raw_damagetype_hashes := payload.get("damageTypeHashes"):
1627            damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes]
1628
1629        default_damagetype_hash: typing.Optional[int] = None
1630        if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"):
1631            default_damagetype_hash = int(raw_defaultdmg_hash)
1632
1633        emblem_objective_hash: typing.Optional[int] = None
1634        if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"):
1635            emblem_objective_hash = int(raw_emblem_obj_hash)
1636
1637        tier_type: typing.Optional[enums.TierType] = None
1638        tier: typing.Optional[enums.ItemTier] = None
1639        bucket_hash: typing.Optional[int] = None
1640        recovery_hash: typing.Optional[int] = None
1641        tier_name: undefined.UndefinedOr[str] = undefined.UNDEFINED
1642        isinstance_item: bool = False
1643        expire_tool_tip: undefined.UndefinedOr[str] = undefined.UNDEFINED
1644        expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.UNDEFINED
1645        suppress_expiration: bool = False
1646        max_stack_size: typing.Optional[int] = None
1647        stack_label: undefined.UndefinedOr[str] = undefined.UNDEFINED
1648
1649        if inventory := payload.get("inventory"):
1650            tier_type = enums.TierType(int(inventory["tierType"]))
1651            tier = enums.ItemTier(int(inventory["tierTypeHash"]))
1652            bucket_hash = int(inventory["bucketTypeHash"])
1653            recovery_hash = int(inventory["recoveryBucketTypeHash"])
1654            tier_name = inventory["tierTypeName"]
1655            isinstance_item = inventory["isInstanceItem"]
1656            suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"]
1657            max_stack_size = int(inventory["maxStackSize"])
1658
1659            try:
1660                stack_label = inventory["stackUniqueLabel"]
1661            except KeyError:
1662                pass
1663
1664        return entity.InventoryEntity(
1665            net=self._net,
1666            collectible_hash=collectible_hash,
1667            name=props.name,
1668            about=about,
1669            emblem_objective_hash=emblem_objective_hash,
1670            suppress_expiration=suppress_expiration,
1671            max_stack_size=max_stack_size,
1672            stack_label=stack_label,
1673            tier=tier,
1674            tier_type=tier_type,
1675            tier_name=tier_name,
1676            bucket_hash=bucket_hash,
1677            recovery_bucket_hash=recovery_hash,
1678            isinstance_item=isinstance_item,
1679            expire_in_orbit_message=expire_in_orbit_message,
1680            expiration_tooltip=expire_tool_tip,
1681            lore_hash=lorehash,
1682            type_and_tier_name=tier_and_name,
1683            summary_hash=summary_hash,
1684            ui_display_style=ui_item_style,
1685            type_name=type_name,
1686            breaker_type_hash=breaker_type_hash,
1687            description=props.description,
1688            display_source=display_source,
1689            hash=props.hash,
1690            damage_types=damage_types,
1691            index=props.index,
1692            icon=props.icon,
1693            has_icon=props.has_icon,
1694            screenshot=screenshot,
1695            watermark_icon=watermark_icon,
1696            watermark_shelved=watermark_shelved,
1697            secondary_icon=secondary_icon,
1698            secondary_overlay=secondary_overlay,
1699            secondary_special=secondary_special,
1700            type=enums.ItemType(int(payload["itemType"])),
1701            trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])],
1702            trait_ids=[trait for trait in payload.get("traitIds", [])],
1703            category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]],
1704            item_class=enums.Class(int(payload["classType"])),
1705            sub_type=enums.ItemSubType(int(payload["itemSubType"])),
1706            breaker_type=int(payload["breakerType"]),
1707            default_damagetype=int(payload["defaultDamageType"]),
1708            default_damagetype_hash=default_damagetype_hash,
1709            damagetype_hashes=damagetype_hashes,
1710            tooltip_notifications=payload["tooltipNotifications"],
1711            not_transferable=payload["nonTransferrable"],
1712            allow_actions=payload["allowActions"],
1713            is_equippable=payload["equippable"],
1714            objects=objects,
1715            background_colors=payload.get("backgroundColor", {}),
1716            season_hash=payload.get("seasonHash"),
1717            has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"],
1718        )
1719
1720    def deserialize_objective_entity(
1721        self, payload: typedefs.JSONObject, /
1722    ) -> entity.ObjectiveEntity:
1723        props = self._set_entity_attrs(payload)
1724        return entity.ObjectiveEntity(
1725            net=self._net,
1726            hash=props.hash,
1727            index=props.index,
1728            description=props.description,
1729            name=props.name,
1730            has_icon=props.has_icon,
1731            icon=props.icon,
1732            unlock_value_hash=payload["unlockValueHash"],
1733            completion_value=payload["completionValue"],
1734            scope=entity.GatingScope(int(payload["scope"])),
1735            location_hash=payload["locationHash"],
1736            allowed_negative_value=payload["allowNegativeValue"],
1737            allowed_value_change=payload["allowValueChangeWhenCompleted"],
1738            counting_downward=payload["isCountingDownward"],
1739            value_style=entity.ValueUIStyle(int(payload["valueStyle"])),
1740            progress_description=payload["progressDescription"],
1741            perks=payload["perks"],
1742            stats=payload["stats"],
1743            minimum_visibility=payload["minimumVisibilityThreshold"],
1744            allow_over_completion=payload["allowOvercompletion"],
1745            show_value_style=payload["showValueOnComplete"],
1746            display_only_objective=payload["isDisplayOnlyObjective"],
1747            complete_value_style=entity.ValueUIStyle(
1748                int(payload["completedValueStyle"])
1749            ),
1750            progress_value_style=entity.ValueUIStyle(
1751                int(payload["inProgressValueStyle"])
1752            ),
1753            ui_label=payload["uiLabel"],
1754            ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])),
1755        )
1756
1757    def _deserialize_activity_values(
1758        self, payload: typedefs.JSONObject, /
1759    ) -> activity.ActivityValues:
1760        team: typing.Optional[int] = None
1761        if raw_team := payload.get("team"):
1762            team = raw_team["basic"]["value"]
1763        return activity.ActivityValues(
1764            assists=payload["assists"]["basic"]["value"],
1765            deaths=payload["deaths"]["basic"]["value"],
1766            kills=payload["kills"]["basic"]["value"],
1767            is_completed=bool(payload["completed"]["basic"]["value"]),
1768            opponents_defeated=payload["opponentsDefeated"]["basic"]["value"],
1769            efficiency=payload["efficiency"]["basic"]["value"],
1770            kd_ratio=payload["killsDeathsRatio"]["basic"]["value"],
1771            kd_assists=payload["killsDeathsAssists"]["basic"]["value"],
1772            score=payload["score"]["basic"]["value"],
1773            duration=payload["activityDurationSeconds"]["basic"]["displayValue"],
1774            team=team,
1775            completion_reason=payload["completionReason"]["basic"]["displayValue"],
1776            fireteam_id=payload["fireteamId"]["basic"]["value"],
1777            start_seconds=payload["startSeconds"]["basic"]["value"],
1778            played_time=payload["timePlayedSeconds"]["basic"]["displayValue"],
1779            player_count=payload["playerCount"]["basic"]["value"],
1780            team_score=payload["teamScore"]["basic"]["value"],
1781        )
1782
1783    def deserialize_activity(
1784        self,
1785        payload: typedefs.JSONObject,
1786        /,
1787    ) -> activity.Activity:
1788        period = time.clean_date(payload["period"])
1789        details = payload["activityDetails"]
1790        ref_id = int(details["referenceId"])
1791        instance_id = int(details["instanceId"])
1792        mode = enums.GameMode(details["mode"])
1793        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1794        is_private = details["isPrivate"]
1795        membership_type = enums.MembershipType(int(details["membershipType"]))
1796
1797        # Since we're using the same fields for post activity method
1798        # this check is required since post activity doesn't values values
1799        values = self._deserialize_activity_values(payload["values"])
1800
1801        return activity.Activity(
1802            net=self._net,
1803            hash=ref_id,
1804            instance_id=instance_id,
1805            mode=mode,
1806            modes=modes,
1807            is_private=is_private,
1808            membership_type=membership_type,
1809            occurred_at=period,
1810            values=values,
1811        )
1812
1813    def deserialize_activities(
1814        self, payload: typedefs.JSONObject
1815    ) -> iterators.Iterator[activity.Activity]:
1816        return iterators.Iterator(
1817            [
1818                self.deserialize_activity(activity_)
1819                for activity_ in payload["activities"]
1820            ]
1821        )
1822
1823    def deserialize_extended_weapon_values(
1824        self, payload: typedefs.JSONObject
1825    ) -> activity.ExtendedWeaponValues:
1826
1827        assists: typing.Optional[int] = None
1828        if raw_assists := payload["values"].get("uniqueWeaponAssists"):
1829            assists = raw_assists["basic"]["value"]
1830        assists_damage: typing.Optional[int] = None
1831
1832        if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"):
1833            assists_damage = raw_assists_damage["basic"]["value"]
1834
1835        return activity.ExtendedWeaponValues(
1836            reference_id=int(payload["referenceId"]),
1837            kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"],
1838            precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][
1839                "value"
1840            ],
1841            assists=assists,
1842            assists_damage=assists_damage,
1843            precision_kills_percentage=(
1844                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"],
1845                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][
1846                    "displayValue"
1847                ],
1848            ),
1849        )
1850
1851    def _deserialize_extended_values(
1852        self, payload: typedefs.JSONObject
1853    ) -> activity.ExtendedValues:
1854        weapons: typing.Optional[
1855            collections.Collection[activity.ExtendedWeaponValues]
1856        ] = None
1857
1858        if raw_weapons := payload.get("weapons"):
1859            weapons = [
1860                self.deserialize_extended_weapon_values(value) for value in raw_weapons
1861            ]
1862
1863        return activity.ExtendedValues(
1864            precision_kills=payload["values"]["precisionKills"]["basic"]["value"],
1865            grenade_kills=payload["values"]["weaponKillsGrenade"]["basic"]["value"],
1866            melee_kills=payload["values"]["weaponKillsMelee"]["basic"]["value"],
1867            super_kills=payload["values"]["weaponKillsSuper"]["basic"]["value"],
1868            ability_kills=payload["values"]["weaponKillsAbility"]["basic"]["value"],
1869            weapons=weapons,
1870        )
1871
1872    def deserialize_post_activity_player(
1873        self, payload: typedefs.JSONObject, /
1874    ) -> activity.PostActivityPlayer:
1875        player = payload["player"]
1876
1877        class_hash: typedefs.NoneOr[int] = None
1878        if (class_hash := player.get("classHash")) is not None:
1879            class_hash = class_hash
1880
1881        race_hash: typedefs.NoneOr[int] = None
1882        if (race_hash := player.get("raceHash")) is not None:
1883            race_hash = race_hash
1884
1885        gender_hash: typedefs.NoneOr[int] = None
1886        if (gender_hash := player.get("genderHash")) is not None:
1887            gender_hash = gender_hash
1888
1889        character_class: undefined.UndefinedOr[str] = undefined.UNDEFINED
1890        if (
1891            character_class := player.get("characterClass")
1892        ) and not typedefs.is_unknown(character_class):
1893            character_class = character_class
1894
1895        character_level: typedefs.NoneOr[int] = None
1896        if (character_level := player.get("characterLevel")) is not None:
1897            character_level = character_level
1898
1899        return activity.PostActivityPlayer(
1900            standing=int(payload["standing"]),
1901            score=int(payload["score"]["basic"]["value"]),
1902            character_id=payload["characterId"],
1903            destiny_user=self.deserialize_destiny_membership(player["destinyUserInfo"]),
1904            character_class=character_class,
1905            character_level=character_level,
1906            race_hash=race_hash,
1907            gender_hash=gender_hash,
1908            class_hash=class_hash,
1909            light_level=int(player["lightLevel"]),
1910            emblem_hash=int(player["emblemHash"]),
1911            values=self._deserialize_activity_values(payload["values"]),
1912            extended_values=self._deserialize_extended_values(payload["extended"]),
1913        )
1914
1915    def _deserialize_post_activity_team(
1916        self, payload: typedefs.JSONObject
1917    ) -> activity.PostActivityTeam:
1918        return activity.PostActivityTeam(
1919            id=payload["teamId"],
1920            is_defeated=bool(payload["standing"]["basic"]["value"]),
1921            score=int(payload["score"]["basic"]["value"]),
1922            name=payload["teamName"],
1923        )
1924
1925    def deserialize_post_activity(
1926        self, payload: typedefs.JSONObject
1927    ) -> activity.PostActivity:
1928        period = time.clean_date(payload["period"])
1929        details = payload["activityDetails"]
1930        ref_id = int(details["referenceId"])
1931        instance_id = int(details["instanceId"])
1932        mode = enums.GameMode(details["mode"])
1933        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1934        is_private = details["isPrivate"]
1935        membership_type = enums.MembershipType(int(details["membershipType"]))
1936        return activity.PostActivity(
1937            net=self._net,
1938            hash=ref_id,
1939            membership_type=membership_type,
1940            instance_id=instance_id,
1941            mode=mode,
1942            modes=modes,
1943            is_private=is_private,
1944            occurred_at=period,
1945            starting_phase=int(payload["startingPhaseIndex"]),
1946            players=[
1947                self.deserialize_post_activity_player(player)
1948                for player in payload["entries"]
1949            ],
1950            teams=[
1951                self._deserialize_post_activity_team(team) for team in payload["teams"]
1952            ],
1953        )
1954
1955    def _deserialize_aggregated_activity_values(
1956        self, payload: typedefs.JSONObject
1957    ) -> activity.AggregatedActivityValues:
1958        # This ID is always the same for all aggregated values.
1959        activity_id = int(payload["fastestCompletionMsForActivity"]["activityId"])
1960
1961        return activity.AggregatedActivityValues(
1962            id=activity_id,
1963            fastest_completion_time=(
1964                int(payload["fastestCompletionMsForActivity"]["basic"]["value"]),
1965                payload["fastestCompletionMsForActivity"]["basic"]["displayValue"],
1966            ),
1967            completions=int(payload["activityCompletions"]["basic"]["value"]),
1968            kills=int(payload["activityKills"]["basic"]["value"]),
1969            deaths=int(payload["activityDeaths"]["basic"]["value"]),
1970            assists=int(payload["activityAssists"]["basic"]["value"]),
1971            seconds_played=(
1972                int(payload["activitySecondsPlayed"]["basic"]["value"]),
1973                payload["activitySecondsPlayed"]["basic"]["displayValue"],
1974            ),
1975            wins=int(payload["activityWins"]["basic"]["value"]),
1976            goals_missed=int(payload["activityGoalsMissed"]["basic"]["value"]),
1977            special_actions=int(payload["activitySpecialActions"]["basic"]["value"]),
1978            best_goals_hit=int(payload["activityBestGoalsHit"]["basic"]["value"]),
1979            best_single_score=int(
1980                payload["activityBestSingleGameScore"]["basic"]["value"]
1981            ),
1982            goals_hit=int(payload["activityGoalsHit"]["basic"]["value"]),
1983            special_score=int(payload["activitySpecialScore"]["basic"]["value"]),
1984            kd_assists=int(payload["activityKillsDeathsAssists"]["basic"]["value"]),
1985            kd_ratio=float(
1986                payload["activityKillsDeathsAssists"]["basic"]["displayValue"]
1987            ),
1988            precision_kills=int(payload["activityPrecisionKills"]["basic"]["value"]),
1989        )
1990
1991    def deserialize_aggregated_activity(
1992        self, payload: typedefs.JSONObject
1993    ) -> activity.AggregatedActivity:
1994        return activity.AggregatedActivity(
1995            hash=int(payload["activityHash"]),
1996            values=self._deserialize_aggregated_activity_values(payload["values"]),
1997        )
1998
1999    def deserialize_aggregated_activities(
2000        self, payload: typedefs.JSONObject
2001    ) -> iterators.Iterator[activity.AggregatedActivity]:
2002        return iterators.Iterator(
2003            [
2004                self.deserialize_aggregated_activity(activity)
2005                for activity in payload["activities"]
2006            ]
2007        )
2008
2009    def deserialize_linked_profiles(
2010        self, payload: typedefs.JSONObject
2011    ) -> profile.LinkedProfile:
2012        bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"])
2013        error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2014        profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2015
2016        if raw_profile := payload.get("profiles"):
2017            for pfile in raw_profile:
2018                profiles_vec.append(self.deserialize_destiny_membership(pfile))
2019
2020        if raw_profiles_with_errors := payload.get("profilesWithErrors"):
2021            for raw_error_pfile in raw_profiles_with_errors:
2022                if error_pfile := raw_error_pfile.get("infoCard"):
2023                    error_profiles_vec.append(
2024                        self.deserialize_destiny_membership(error_pfile)
2025                    )
2026
2027        return profile.LinkedProfile(
2028            net=self._net,
2029            bungie=bungie_user,
2030            profiles=profiles_vec,
2031            profiles_with_errors=error_profiles_vec,
2032        )
2033
2034    def deserialize_clan_banners(
2035        self, payload: typedefs.JSONObject
2036    ) -> collections.Sequence[clans.ClanBanner]:
2037        banners_seq: typing.MutableSequence[clans.ClanBanner] = []
2038        if banners := payload.get("clanBannerDecals"):
2039            for k, v in banners.items():
2040                banner_obj = clans.ClanBanner(
2041                    id=int(k),
2042                    foreground=assets.Image(v["foregroundPath"]),
2043                    background=assets.Image(v["backgroundPath"]),
2044                )
2045                banners_seq.append(banner_obj)
2046        return banners_seq
2047
2048    def deserialize_public_milestone_content(
2049        self, payload: typedefs.JSONObject
2050    ) -> milestones.MilestoneContent:
2051        items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None
2052        if raw_categories := payload.get("itemCategories"):
2053            for item in raw_categories:
2054                title = undefined.UNDEFINED
2055                if raw_title := item.get("title"):
2056                    if raw_title != typedefs.Unknown:
2057                        title = raw_title
2058                if raw_hashes := item.get("itemHashes"):
2059                    hashes: collections.Sequence[int] = raw_hashes
2060
2061                items_categoris = milestones.MilestoneItems(title=title, hashes=hashes)
2062
2063        about = undefined.UNDEFINED
2064        if (raw_about := payload["about"]) != typedefs.Unknown:
2065            about = raw_about
2066
2067        status = undefined.UNDEFINED
2068        if (raw_status := payload["status"]) != typedefs.Unknown:
2069            status = raw_status
2070
2071        tips: typing.MutableSequence[undefined.UndefinedOr[str]] = []
2072        if raw_tips := payload.get("tips"):
2073            for raw_tip in raw_tips:
2074                if raw_tip == typedefs.Unknown:
2075                    raw_tip = undefined.UNDEFINED
2076                tips.append(raw_tip)
2077
2078        return milestones.MilestoneContent(
2079            about=about, status=status, tips=tips, items=items_categoris
2080        )
2081
2082    def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend:
2083        name = undefined.UNDEFINED
2084        if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown:
2085            name = raw_name
2086
2087        bungie_user: typedefs.NoneOr[user.BungieUser] = None
2088
2089        if raw_bungie_user := payload.get("bungieNetUser"):
2090            bungie_user = self.deserialize_bungie_user(raw_bungie_user)
2091
2092        return friends.Friend(
2093            net=self._net,
2094            id=int(payload["lastSeenAsMembershipId"]),
2095            name=name,
2096            code=payload.get("bungieGlobalDisplayNameCode"),
2097            relationship=enums.Relationship(payload["relationship"]),
2098            user=bungie_user,
2099            online_status=enums.Presence(payload["onlineStatus"]),
2100            online_title=payload["onlineTitle"],
2101            type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]),
2102        )
2103
2104    def deserialize_friends(
2105        self, payload: typedefs.JSONObject
2106    ) -> collections.Sequence[friends.Friend]:
2107        mut_seq: typing.MutableSequence[friends.Friend] = []
2108        if raw_friends := payload.get("friends"):
2109            for friend in raw_friends:
2110                mut_seq.append(self.deserialize_friend(friend))
2111        return mut_seq
2112
2113    def deserialize_friend_requests(
2114        self, payload: typedefs.JSONObject
2115    ) -> friends.FriendRequestView:
2116        incoming: typing.MutableSequence[friends.Friend] = []
2117        outgoing: typing.MutableSequence[friends.Friend] = []
2118
2119        if raw_incoming_requests := payload.get("incomingRequests"):
2120            for incoming_request in raw_incoming_requests:
2121                incoming.append(self.deserialize_friend(incoming_request))
2122
2123        if raw_outgoing_requests := payload.get("outgoingRequests"):
2124            for outgoing_request in raw_outgoing_requests:
2125                outgoing.append(self.deserialize_friend(outgoing_request))
2126
2127        return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)
2128
2129    def _set_fireteam_fields(
2130        self, payload: typedefs.JSONObject, total_results: typing.Optional[int] = None
2131    ) -> fireteams.Fireteam:
2132        activity_type = fireteams.FireteamActivity(payload["activityType"])
2133        return fireteams.Fireteam(
2134            id=int(payload["fireteamId"]),
2135            group_id=int(payload["groupId"]),
2136            platform=fireteams.FireteamPlatform(payload["platform"]),
2137            is_immediate=payload["isImmediate"],
2138            activity_type=activity_type,
2139            owner_id=int(payload["ownerMembershipId"]),
2140            player_slot_count=payload["playerSlotCount"],
2141            available_player_slots=payload["availablePlayerSlotCount"],
2142            available_alternate_slots=payload["availableAlternateSlotCount"],
2143            title=payload["title"],
2144            date_created=time.clean_date(payload["dateCreated"]),
2145            is_public=payload["isPublic"],
2146            locale=fireteams.FireteamLanguage(payload["locale"]),
2147            is_valid=payload["isValid"],
2148            last_modified=time.clean_date(payload["datePlayerModified"]),
2149            total_results=total_results or 0,
2150        )
2151
2152    def deserialize_fireteams(
2153        self, payload: typedefs.JSONObject
2154    ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]:
2155        fireteams_: typing.MutableSequence[fireteams.Fireteam] = []
2156
2157        result: list[typedefs.JSONObject]
2158        if not (result := payload["results"]):
2159            return None
2160        for elem in result:
2161            fireteams_.append(
2162                self._set_fireteam_fields(
2163                    elem, total_results=int(payload["totalResults"])
2164                )
2165            )
2166        return fireteams_
2167
2168    def deserialize_fireteam_destiny_users(
2169        self, payload: typedefs.JSONObject
2170    ) -> fireteams.FireteamUser:
2171        destiny_obj = self.deserialize_destiny_membership(payload)
2172        # We could helpers.just return a DestinyMembership object but this is
2173        # missing the fireteam display name and id fields.
2174        return fireteams.FireteamUser(
2175            net=self._net,
2176            id=destiny_obj.id,
2177            code=destiny_obj.code,
2178            icon=destiny_obj.icon,
2179            types=destiny_obj.types,
2180            type=destiny_obj.type,
2181            is_public=destiny_obj.is_public,
2182            crossave_override=destiny_obj.crossave_override,
2183            name=destiny_obj.name,
2184            last_seen_name=destiny_obj.last_seen_name,
2185            fireteam_display_name=payload["FireteamDisplayName"],
2186            fireteam_membership_id=enums.MembershipType(
2187                payload["FireteamMembershipType"]
2188            ),
2189        )
2190
2191    def deserialize_fireteam_members(
2192        self, payload: typedefs.JSONObject, *, alternatives: bool = False
2193    ) -> typing.Optional[collections.Sequence[fireteams.FireteamMember]]:
2194        members_: list[fireteams.FireteamMember] = []
2195        if members := payload.get("Members" if not alternatives else "Alternates"):
2196            for member in members:
2197                bungie_fields = self.deserialize_partial_bungie_user(member)
2198                members_fields = fireteams.FireteamMember(
2199                    destiny_user=self.deserialize_fireteam_destiny_users(member),
2200                    has_microphone=member["hasMicrophone"],
2201                    character_id=int(member["characterId"]),
2202                    date_joined=time.clean_date(member["dateJoined"]),
2203                    last_platform_invite_date=time.clean_date(
2204                        member["lastPlatformInviteAttemptDate"]
2205                    ),
2206                    last_platform_invite_result=int(
2207                        member["lastPlatformInviteAttemptResult"]
2208                    ),
2209                    net=self._net,
2210                    name=bungie_fields.name,
2211                    id=bungie_fields.id,
2212                    icon=bungie_fields.icon,
2213                    is_public=bungie_fields.is_public,
2214                    crossave_override=bungie_fields.crossave_override,
2215                    types=bungie_fields.types,
2216                    type=bungie_fields.type,
2217                )
2218                members_.append(members_fields)
2219        else:
2220            return None
2221        return members_
2222
2223    def deserialize_available_fireteams(
2224        self,
2225        data: typedefs.JSONObject,
2226        *,
2227        no_results: bool = False,
2228    ) -> typing.Union[
2229        fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam]
2230    ]:
2231        fireteams_: list[fireteams.AvailableFireteam] = []
2232
2233        # This needs to be used outside the results
2234        # JSON key.
2235        if no_results is True:
2236            payload = data
2237
2238        if result := payload.get("results"):
2239
2240            for fireteam in result:
2241                found_fireteams = self._set_fireteam_fields(fireteam["Summary"])
2242                fireteams_fields = fireteams.AvailableFireteam(
2243                    id=found_fireteams.id,
2244                    group_id=found_fireteams.group_id,
2245                    platform=found_fireteams.platform,
2246                    activity_type=found_fireteams.activity_type,
2247                    is_immediate=found_fireteams.is_immediate,
2248                    is_public=found_fireteams.is_public,
2249                    is_valid=found_fireteams.is_valid,
2250                    owner_id=found_fireteams.owner_id,
2251                    player_slot_count=found_fireteams.player_slot_count,
2252                    available_player_slots=found_fireteams.available_player_slots,
2253                    available_alternate_slots=found_fireteams.available_alternate_slots,
2254                    title=found_fireteams.title,
2255                    date_created=found_fireteams.date_created,
2256                    locale=found_fireteams.locale,
2257                    last_modified=found_fireteams.last_modified,
2258                    total_results=found_fireteams.total_results,
2259                    members=self.deserialize_fireteam_members(payload),
2260                    alternatives=self.deserialize_fireteam_members(
2261                        payload, alternatives=True
2262                    ),
2263                )
2264            fireteams_.append(fireteams_fields)
2265            if no_results:
2266                return fireteams_fields
2267        return fireteams_
2268
2269    def deserialize_fireteam_party(
2270        self, payload: typedefs.JSONObject
2271    ) -> fireteams.FireteamParty:
2272        last_destination_hash: typing.Optional[int] = None
2273        if raw_dest_hash := payload.get("lastOrbitedDestinationHash"):
2274            last_destination_hash = int(raw_dest_hash)
2275
2276        return fireteams.FireteamParty(
2277            members=[
2278                self._deserialize_fireteam_party_member(member)
2279                for member in payload["partyMembers"]
2280            ],
2281            activity=self._deserialize_fireteam_party_current_activity(
2282                payload["currentActivity"]
2283            ),
2284            settings=self._deserialize_fireteam_party_settings(payload["joinability"]),
2285            last_destination_hash=last_destination_hash,
2286            tracking=payload["tracking"],
2287        )
2288
2289    def _deserialize_fireteam_party_member(
2290        self, payload: typedefs.JSONObject
2291    ) -> fireteams.FireteamPartyMember:
2292
2293        status = fireteams.FireteamPartyMemberState(payload["status"])
2294        displayname: undefined.UndefinedOr[str] = undefined.UNDEFINED
2295        if raw_name := payload.get("displayName"):
2296            displayname = raw_name
2297
2298        return fireteams.FireteamPartyMember(
2299            membership_id=int(payload["membershipId"]),
2300            emblem_hash=int(payload["emblemHash"]),
2301            status=status,
2302            display_name=displayname,
2303        )
2304
2305    def _deserialize_fireteam_party_current_activity(
2306        self, payload: typedefs.JSONObject
2307    ) -> fireteams.FireteamPartyCurrentActivity:
2308        start_date: typing.Optional[datetime.datetime] = None
2309        if raw_start_date := payload.get("startTime"):
2310            start_date = time.clean_date(raw_start_date)
2311
2312        end_date: typing.Optional[datetime.datetime] = None
2313        if raw_end_date := payload.get("endTime"):
2314            end_date = time.clean_date(raw_end_date)
2315        return fireteams.FireteamPartyCurrentActivity(
2316            start_time=start_date,
2317            end_time=end_date,
2318            score=float(payload["score"]),
2319            highest_opposing_score=float(payload["highestOpposingFactionScore"]),
2320            opponenst_count=int(payload["numberOfOpponents"]),
2321            player_count=int(payload["numberOfPlayers"]),
2322        )
2323
2324    def _deserialize_fireteam_party_settings(
2325        self, payload: typedefs.JSONObject
2326    ) -> fireteams.FireteamPartySettings:
2327        closed_reasons = enums.ClosedReasons(payload["closedReasons"])
2328        return fireteams.FireteamPartySettings(
2329            open_slots=int(payload["openSlots"]),
2330            privacy_setting=enums.PrivacySetting(int(payload["privacySetting"])),
2331            closed_reasons=closed_reasons,
2332        )
2333
2334    def deserialize_seasonal_artifact(
2335        self, payload: typedefs.JSONObject
2336    ) -> season.Artifact:
2337        if raw_artifact := payload.get("seasonalArtifact"):
2338            if points := raw_artifact.get("pointProgression"):
2339                points_prog = progressions.Progression(
2340                    hash=points["progressionHash"],
2341                    level=points["level"],
2342                    cap=points["levelCap"],
2343                    daily_limit=points["dailyLimit"],
2344                    weekly_limit=points["weeklyLimit"],
2345                    current_progress=points["currentProgress"],
2346                    daily_progress=points["dailyProgress"],
2347                    needed=points["progressToNextLevel"],
2348                    next_level=points["nextLevelAt"],
2349                )
2350
2351            if bonus := raw_artifact.get("powerBonusProgression"):
2352                power_bonus_prog = progressions.Progression(
2353                    hash=bonus["progressionHash"],
2354                    level=bonus["level"],
2355                    cap=bonus["levelCap"],
2356                    daily_limit=bonus["dailyLimit"],
2357                    weekly_limit=bonus["weeklyLimit"],
2358                    current_progress=bonus["currentProgress"],
2359                    daily_progress=bonus["dailyProgress"],
2360                    needed=bonus["progressToNextLevel"],
2361                    next_level=bonus["nextLevelAt"],
2362                )
2363            artifact = season.Artifact(
2364                net=self._net,
2365                hash=raw_artifact["artifactHash"],
2366                power_bonus=raw_artifact["powerBonus"],
2367                acquired_points=raw_artifact["pointsAcquired"],
2368                bonus=power_bonus_prog,
2369                points=points_prog,
2370            )
2371        return artifact
2372
2373    def deserialize_profile_progression(
2374        self, payload: typedefs.JSONObject
2375    ) -> profile.ProfileProgression:
2376        return profile.ProfileProgression(
2377            artifact=self.deserialize_seasonal_artifact(payload["data"]),
2378            checklist={
2379                int(check_id): checklists
2380                for check_id, checklists in payload["data"]["checklists"].items()
2381            },
2382        )
2383
2384    def deserialize_instanced_item(
2385        self, payload: typedefs.JSONObject
2386    ) -> items.ItemInstance:
2387        damage_type_hash: typing.Optional[int] = None
2388        if raw_damagetype_hash := payload.get("damageTypeHash"):
2389            damage_type_hash = int(raw_damagetype_hash)
2390
2391        required_hashes: typing.Optional[collections.Collection[int]] = None
2392        if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"):
2393            required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes]
2394
2395        breaker_type: typing.Optional[items.ItemBreakerType] = None
2396        if raw_break_type := payload.get("breakerType"):
2397            breaker_type = items.ItemBreakerType(int(raw_break_type))
2398
2399        breaker_type_hash: typing.Optional[int] = None
2400        if raw_break_type_hash := payload.get("breakerTypeHash"):
2401            breaker_type_hash = int(raw_break_type_hash)
2402
2403        energy: typing.Optional[items.ItemEnergy] = None
2404        if raw_energy := payload.get("energy"):
2405            energy = self.deserialize_item_energy(raw_energy)
2406
2407        primary_stats = None
2408        if raw_primary_stats := payload.get("primaryStat"):
2409            primary_stats = self.deserialize_item_stats_view(raw_primary_stats)
2410
2411        return items.ItemInstance(
2412            damage_type=enums.DamageType(int(payload["damageType"])),
2413            damage_type_hash=damage_type_hash,
2414            primary_stat=primary_stats,
2415            item_level=int(payload["itemLevel"]),
2416            quality=int(payload["quality"]),
2417            is_equipped=payload["isEquipped"],
2418            can_equip=payload["canEquip"],
2419            equip_required_level=int(payload["equipRequiredLevel"]),
2420            required_equip_unlock_hashes=required_hashes,
2421            cant_equip_reason=int(payload["cannotEquipReason"]),
2422            breaker_type=breaker_type,
2423            breaker_type_hash=breaker_type_hash,
2424            energy=energy,
2425        )
2426
2427    def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy:
2428        energy_hash: typing.Optional[int] = None
2429        if raw_energy_hash := payload.get("energyTypeHash"):
2430            energy_hash = int(raw_energy_hash)
2431
2432        return items.ItemEnergy(
2433            hash=energy_hash,
2434            type=items.ItemEnergyType(int(payload["energyType"])),
2435            capacity=int(payload["energyCapacity"]),
2436            used_energy=int(payload["energyUsed"]),
2437            unused_energy=int(payload["energyUnused"]),
2438        )
2439
2440    def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk:
2441        perk_hash: typing.Optional[int] = None
2442        if raw_perk_hash := payload.get("perkHash"):
2443            perk_hash = int(raw_perk_hash)
2444
2445        return items.ItemPerk(
2446            hash=perk_hash,
2447            icon=assets.Image(payload["iconPath"]),
2448            is_active=payload["isActive"],
2449            is_visible=payload["visible"],
2450        )
2451
2452    def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket:
2453        plug_hash: typing.Optional[int] = None
2454        if raw_plug_hash := payload.get("plugHash"):
2455            plug_hash = int(raw_plug_hash)
2456
2457        enable_fail_indexes: typing.Optional[list[int]] = None
2458        if raw_indexes := payload.get("enableFailIndexes"):
2459            enable_fail_indexes = [int(index) for index in raw_indexes]
2460
2461        return items.ItemSocket(
2462            plug_hash=plug_hash,
2463            is_enabled=payload["isEnabled"],
2464            enable_fail_indexes=enable_fail_indexes,
2465            is_visible=payload.get("visible"),
2466        )
2467
2468    def deserialize_item_stats_view(
2469        self, payload: typedefs.JSONObject
2470    ) -> items.ItemStatsView:
2471        return items.ItemStatsView(
2472            stat_hash=payload.get("statHash"), value=payload.get("value")
2473        )
2474
2475    def deserialize_plug_item_state(
2476        self, payload: typedefs.JSONObject
2477    ) -> items.PlugItemState:
2478        item_hash: typing.Optional[int] = None
2479        if raw_item_hash := payload.get("plugItemHash"):
2480            item_hash = int(raw_item_hash)
2481
2482        insert_fail_indexes: typedefs.NoneOr[list[int]] = None
2483        if raw_fail_indexes := payload.get("insertFailIndexes"):
2484            insert_fail_indexes = [int(k) for k in raw_fail_indexes]
2485
2486        enable_fail_indexes: typedefs.NoneOr[list[int]] = None
2487        if raw_enabled_indexes := payload.get("enableFailIndexes"):
2488            enable_fail_indexes = [int(k) for k in raw_enabled_indexes]
2489
2490        return items.PlugItemState(
2491            item_hash=item_hash,
2492            insert_fail_indexes=insert_fail_indexes,
2493            enable_fail_indexes=enable_fail_indexes,
2494            is_enabled=payload["enabled"],
2495            can_insert=payload["canInsert"],
2496        )

The base deserialization factory class for all aiobungie objects.

Highly inspired hikari entity factory used to deserialize JSON responses from the REST client and turning them into a aiobungie.crates Python classes.

Factory(net: aiobungie.traits.Netrunner)
70    def __init__(self, net: traits.Netrunner) -> None:
71        self._net = net
def deserialize_bungie_user(self, data: dict[str, typing.Any]) -> aiobungie.crates.user.BungieUser:
73    def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser:
74        return user.BungieUser(
75            id=int(data["membershipId"]),
76            created_at=time.clean_date(data["firstAccess"]),
77            name=data.get("cachedBungieGlobalDisplayName", undefined.UNDEFINED),
78            is_deleted=data["isDeleted"],
79            about=data["about"],
80            updated_at=time.clean_date(data["lastUpdate"]),
81            psn_name=data.get("psnDisplayName", None),
82            stadia_name=data.get("stadiaDisplayName", None),
83            steam_name=data.get("steamDisplayName", None),
84            twitch_name=data.get("twitchDisplayName", None),
85            blizzard_name=data.get("blizzardDisplayName", None),
86            status=data["statusText"],
87            locale=data["locale"],
88            picture=assets.Image(path=str(data["profilePicturePath"])),
89            code=data.get("cachedBungieGlobalDisplayNameCode", None),
90            unique_name=data.get("uniqueName", None),
91            theme_id=int(data["profileTheme"]),
92            show_activity=bool(data["showActivity"]),
93            theme_name=data["profileThemeName"],
94            display_title=data["userTitleDisplay"],
95        )

Deserialize a raw JSON Bungie.net user only payload into a user object.

This only returns the Bungie.net user and not the Destiny memberships.

Parameters
Returns
def deserialize_partial_bungie_user( self, payload: dict[str, typing.Any]) -> aiobungie.crates.user.PartialBungieUser:
 97    def deserialize_partial_bungie_user(
 98        self, payload: typedefs.JSONObject
 99    ) -> user.PartialBungieUser:
100        return user.PartialBungieUser(
101            net=self._net,
102            types=[
103                enums.MembershipType(type_)
104                for type_ in payload.get("applicableMembershipTypes", [])
105            ],
106            name=payload.get("displayName", undefined.UNDEFINED),
107            id=int(payload["membershipId"]),
108            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
109            is_public=payload["isPublic"],
110            icon=assets.Image(payload.get("iconPath", "")),
111            type=enums.MembershipType(payload["membershipType"]),
112        )

Deserialize a raw JSON of a partial bungieNetUserInfo.

A partial user is a bungie.net user payload with missing information from the main BungieUser object.

Parameters
Returns
def deserialize_destiny_membership( self, payload: dict[str, typing.Any]) -> aiobungie.crates.user.DestinyMembership:
114    def deserialize_destiny_membership(
115        self, payload: typedefs.JSONObject
116    ) -> user.DestinyMembership:
117        name: undefined.UndefinedOr[str] = undefined.UNDEFINED
118        if (
119            raw_name := payload.get("bungieGlobalDisplayName", "")
120        ) and not typedefs.is_unknown(raw_name):
121            name = raw_name
122
123        return user.DestinyMembership(
124            net=self._net,
125            id=int(payload["membershipId"]),
126            name=name,
127            code=payload.get("bungieGlobalDisplayNameCode", None),
128            last_seen_name=payload.get("LastSeenDisplayName")
129            or payload.get("displayName")  # noqa: W503
130            or "",  # noqa: W503
131            type=enums.MembershipType(payload["membershipType"]),
132            is_public=payload["isPublic"],
133            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
134            icon=assets.Image(payload.get("iconPath", "")),
135            types=[
136                enums.MembershipType(type_)
137                for type_ in payload.get("applicableMembershipTypes", [])
138            ],
139        )

Deserialize a raw JSON of destinyUserInfo destiny membership information.

Parameters
Returns
  • aiobungie.crates.user.DestinyMembership: A Destiny 2 membership.
def deserialize_destiny_memberships( self, data: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.user.DestinyMembership]:
141    def deserialize_destiny_memberships(
142        self, data: typedefs.JSONArray
143    ) -> collections.Sequence[user.DestinyMembership]:
144        return [self.deserialize_destiny_membership(membership) for membership in data]

Deserialize a raw JSON payload/array of destinyUserInfo.

Parameters
Returns
  • collections.Sequence[aiobungie.crates.user.DestinyMembership]: A sequence of Destiny 2 memberships.
def deserialize_user(self, data: dict[str, typing.Any]) -> aiobungie.crates.user.User:
146    def deserialize_user(self, data: typedefs.JSONObject) -> user.User:
147
148        primary_membership_id: typing.Optional[int] = None
149        if raw_primary_id := data.get("primaryMembershipId"):
150            primary_membership_id = int(raw_primary_id)
151
152        return user.User(
153            bungie=self.deserialize_bungie_user(data["bungieNetUser"]),
154            destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]),
155            primary_membership_id=primary_membership_id,
156        )

Deserialize a raw JSON results of fetched user memberships and Bungie.net user its their id.

Parameters
Returns
def deserialize_searched_user( self, payload: dict[str, typing.Any]) -> aiobungie.crates.user.SearchableDestinyUser:
158    def deserialize_searched_user(
159        self, payload: typedefs.JSONObject
160    ) -> user.SearchableDestinyUser:
161        name: undefined.UndefinedOr[str] = undefined.UNDEFINED
162        if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown(
163            raw_name
164        ):
165            name = raw_name
166
167        code: typing.Optional[int] = None
168        if raw_code := payload.get("bungieGlobalDisplayNameCode"):
169            code = int(raw_code)
170
171        bungie_id: typing.Optional[int] = None
172        if raw_bungie_id := payload.get("bungieNetMembershipId"):
173            bungie_id = int(raw_bungie_id)
174
175        return user.SearchableDestinyUser(
176            name=name,
177            code=code,
178            bungie_id=bungie_id,
179            memberships=self.deserialize_destiny_memberships(
180                payload["destinyMemberships"]
181            ),
182        )

Deserialize the results of user search details.

Parameters
Returns
def deserialize_user_credentials( self, payload: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.user.UserCredentials]:
184    def deserialize_user_credentials(
185        self, payload: typedefs.JSONArray
186    ) -> collections.Sequence[user.UserCredentials]:
187        return [
188            user.UserCredentials(
189                type=enums.CredentialType(int(creds["credentialType"])),
190                display_name=creds["credentialDisplayName"],
191                is_public=creds["isPublic"],
192                self_as_string=creds.get("credentialAsString", undefined.UNDEFINED),
193            )
194            for creds in payload
195        ]

Deserialize a JSON array of Bungie user credentials.

Parameters
Returns
def deserialize_user_themes( self, payload: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.user.UserThemes]:
197    def deserialize_user_themes(
198        self, payload: typedefs.JSONArray
199    ) -> collections.Sequence[user.UserThemes]:
200        return [
201            user.UserThemes(
202                id=int(entry["userThemeId"]),
203                name=entry["userThemeName"]
204                if "userThemeName" in entry
205                else undefined.UNDEFINED,
206                description=entry["userThemeDescription"]
207                if "userThemeDescription" in entry
208                else undefined.UNDEFINED,
209            )
210            for entry in payload
211        ]

Deserialize a raw JSON array of Bungie user themes.

Parameters
Returns
  • collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of bungie user themes.
def deserialize_clan(self, payload: dict[str, typing.Any]) -> aiobungie.crates.clans.Clan:
213    def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan:
214
215        # This is kinda redundant
216        data = payload
217
218        # This is always outside the details.
219        current_user_map: typing.Optional[
220            collections.Mapping[str, clans.ClanMember]
221        ] = None
222        if raw_current_user_map := payload.get("currentUserMemberMap"):
223            current_user_map = {
224                membership_type: self.deserialize_clan_member(membership)
225                for membership_type, membership in raw_current_user_map.items()
226            }
227
228        try:
229            data = payload["detail"]
230        except KeyError:
231            pass
232
233        id = data["groupId"]
234        name = data["name"]
235        created_at = data["creationDate"]
236        member_count = data["memberCount"]
237        about = data["about"]
238        motto = data["motto"]
239        is_public = data["isPublic"]
240        banner = assets.Image(str(data["bannerPath"]))
241        avatar = assets.Image(str(data["avatarPath"]))
242        tags = data["tags"]
243        type = data["groupType"]
244
245        features = data["features"]
246        features_obj = clans.ClanFeatures(
247            max_members=features["maximumMembers"],
248            max_membership_types=features["maximumMembershipsOfGroupType"],
249            capabilities=features["capabilities"],
250            membership_types=features["membershipTypes"],
251            invite_permissions=features["invitePermissionOverride"],
252            update_banner_permissions=features["updateBannerPermissionOverride"],
253            update_culture_permissions=features["updateCulturePermissionOverride"],
254            join_level=features["joinLevel"],
255        )
256
257        information: typedefs.JSONObject = data["clanInfo"]
258        progression: collections.Mapping[int, progressions.Progression] = {
259            int(prog_hash): self.deserialize_progressions(prog)
260            for prog_hash, prog in information["d2ClanProgressions"].items()
261        }
262
263        founder: typedefs.NoneOr[clans.ClanMember] = None
264        if raw_founder := payload.get("founder"):
265            founder = self.deserialize_clan_member(raw_founder)
266
267        return clans.Clan(
268            net=self._net,
269            id=int(id),
270            name=name,
271            type=enums.GroupType(type),
272            created_at=time.clean_date(created_at),
273            member_count=member_count,
274            motto=motto,
275            about=about,
276            is_public=is_public,
277            banner=banner,
278            avatar=avatar,
279            tags=tags,
280            features=features_obj,
281            owner=founder,
282            progressions=progression,
283            call_sign=information["clanCallsign"],
284            banner_data=information["clanBannerData"],
285            chat_security=data["chatSecurity"],
286            conversation_id=int(data["conversationId"]),
287            allow_chat=data["allowChat"],
288            theme=data["theme"],
289            current_user_membership=current_user_map,
290        )

Deserialize a raw JSON payload of Bungie clan information.

Parameters
Returns
def deserialize_clan_member( self, data: dict[str, typing.Any], /) -> aiobungie.crates.clans.ClanMember:
292    def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember:
293        destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"])
294        return clans.ClanMember(
295            net=self._net,
296            last_seen_name=destiny_user.last_seen_name,
297            id=destiny_user.id,
298            name=destiny_user.name,
299            icon=destiny_user.icon,
300            last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])),
301            group_id=int(data["groupId"]),
302            joined_at=time.clean_date(data["joinDate"]),
303            types=destiny_user.types,
304            is_public=destiny_user.is_public,
305            type=destiny_user.type,
306            code=destiny_user.code,
307            is_online=data["isOnline"],
308            crossave_override=destiny_user.crossave_override,
309            bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"])
310            if "bungieNetUserInfo" in data
311            else None,
312            member_type=enums.ClanMemberType(int(data["memberType"])),
313        )

Deserialize a JSON payload of a clan member information.

Parameters
Returns
def deserialize_clan_members( self, data: dict[str, typing.Any], /) -> aiobungie.Iterator[aiobungie.crates.clans.ClanMember]:
315    def deserialize_clan_members(
316        self, data: typedefs.JSONObject, /
317    ) -> iterators.Iterator[clans.ClanMember]:
318        return iterators.Iterator(
319            [self.deserialize_clan_member(member) for member in data["results"]]
320        )

Deserialize a JSON payload of a clan members information.

Parameters
Returns
def deserialize_group_member( self, payload: dict[str, typing.Any]) -> aiobungie.crates.clans.GroupMember:
322    def deserialize_group_member(
323        self, payload: typedefs.JSONObject
324    ) -> clans.GroupMember:
325        member = payload["member"]
326        return clans.GroupMember(
327            net=self._net,
328            join_date=time.clean_date(member["joinDate"]),
329            group_id=int(member["groupId"]),
330            member_type=enums.ClanMemberType(member["memberType"]),
331            is_online=member["isOnline"],
332            last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])),
333            inactive_memberships=payload.get("areAllMembershipsInactive", None),
334            member=self.deserialize_destiny_membership(member["destinyUserInfo"]),
335            group=self.deserialize_clan(payload["group"]),
336        )

Deserialize a JSON payload of group information for a member.

Parameters
Returns
def deserialize_clan_conversations( self, payload: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.clans.ClanConversation]:
354    def deserialize_clan_conversations(
355        self, payload: typedefs.JSONArray
356    ) -> collections.Sequence[clans.ClanConversation]:
357        return [self._deserialize_clan_conversation(conv) for conv in payload]

Deserialize a JSON array of a clan conversations information.

Parameters
Returns
def deserialize_app_owner( self, payload: dict[str, typing.Any]) -> aiobungie.crates.application.ApplicationOwner:
359    def deserialize_app_owner(
360        self, payload: typedefs.JSONObject
361    ) -> application.ApplicationOwner:
362        return application.ApplicationOwner(
363            net=self._net,
364            name=payload.get("bungieGlobalDisplayName", undefined.UNDEFINED),
365            id=int(payload["membershipId"]),
366            type=enums.MembershipType(payload["membershipType"]),
367            icon=assets.Image(str(payload["iconPath"])),
368            is_public=payload["isPublic"],
369            code=payload.get("bungieGlobalDisplayNameCode", None),
370        )

Deserialize a JSON payload of Bungie Developer portal application owner information.

Parameters
Returns
  • aiobungie.crates.application.ApplicationOwner: An application owner.
def deserialize_app( self, payload: dict[str, typing.Any]) -> aiobungie.crates.application.Application:
372    def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application:
373        return application.Application(
374            id=int(payload["applicationId"]),
375            name=payload["name"],
376            link=payload["link"],
377            status=payload["status"],
378            redirect_url=payload.get("redirectUrl", None),
379            created_at=time.clean_date(str(payload["creationDate"])),
380            published_at=time.clean_date(str(payload["firstPublished"])),
381            owner=self.deserialize_app_owner(payload["team"][0]["user"]),  # type: ignore
382            scope=payload.get("scope", undefined.UNDEFINED),
383        )

Deserialize a JSON payload of Bungie Developer portal application information.

Parameters
Returns
  • aiobungie.crates.application.Application: An application.
def deserialize_profile( self, payload: dict[str, typing.Any], /) -> Optional[aiobungie.crates.profile.Profile]:
406    def deserialize_profile(
407        self, payload: typedefs.JSONObject, /
408    ) -> typing.Optional[profile.Profile]:
409        if (raw_profile := payload.get("data")) is None:
410            return None
411
412        payload = raw_profile
413        id = int(payload["userInfo"]["membershipId"])
414        name = payload["userInfo"]["displayName"]
415        is_public = payload["userInfo"]["isPublic"]
416        type = enums.MembershipType(payload["userInfo"]["membershipType"])
417        last_played = time.clean_date(str(payload["dateLastPlayed"]))
418        character_ids = [int(cid) for cid in payload["characterIds"]]
419        power_cap = payload["currentSeasonRewardPowerCap"]
420
421        return profile.Profile(
422            id=int(id),
423            name=name,
424            is_public=is_public,
425            type=type,
426            last_played=last_played,
427            character_ids=character_ids,
428            power_cap=power_cap,
429            net=self._net,
430        )

Deserialize a JSON payload of Bungie.net profile information.

Parameters
Returns
def deserialize_profile_item( self, payload: dict[str, typing.Any]) -> aiobungie.crates.profile.ProfileItemImpl:
432    def deserialize_profile_item(
433        self, payload: typedefs.JSONObject
434    ) -> profile.ProfileItemImpl:
435
436        instance_id: typing.Optional[int] = None
437        if raw_instance_id := payload.get("itemInstanceId"):
438            instance_id = int(raw_instance_id)
439
440        version_number: typing.Optional[int] = None
441        if raw_version := payload.get("versionNumber"):
442            version_number = int(raw_version)
443
444        transfer_status = enums.TransferStatus(payload["transferStatus"])
445
446        return profile.ProfileItemImpl(
447            net=self._net,
448            hash=payload["itemHash"],
449            quantity=payload["quantity"],
450            bind_status=enums.ItemBindStatus(payload["bindStatus"]),
451            location=enums.ItemLocation(payload["location"]),
452            bucket=payload["bucketHash"],
453            transfer_status=transfer_status,
454            lockable=payload["lockable"],
455            state=enums.ItemState(payload["state"]),
456            dismantel_permissions=payload["dismantlePermission"],
457            is_wrapper=payload["isWrapper"],
458            instance_id=instance_id,
459            version_number=version_number,
460            ornament_id=payload.get("overrideStyleItemHash"),
461        )

Deserialize a JSON payload of a singular profile component item.

Parameters
Returns
def deserialize_objectives( self, payload: dict[str, typing.Any]) -> aiobungie.crates.records.Objective:
463    def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective:
464        return records.Objective(
465            net=self._net,
466            hash=payload["objectiveHash"],
467            visible=payload["visible"],
468            complete=payload["complete"],
469            completion_value=payload["completionValue"],
470            progress=payload.get("progress"),
471            destination_hash=payload.get("destinationHash"),
472            activity_hash=payload.get("activityHash"),
473        )

Deserialize a JSON payload of an objective found in a record profile component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
  • aiobungie.crates.records.Objective: A record objective object.
def deserialize_records( self, payload: dict[str, typing.Any], scores: Optional[aiobungie.crates.records.RecordScores] = None, **nodes: int) -> aiobungie.crates.records.Record:
475    def deserialize_records(
476        self,
477        payload: typedefs.JSONObject,
478        scores: typing.Optional[records.RecordScores] = None,
479        **nodes: int,
480    ) -> records.Record:
481        objectives: typing.Optional[list[records.Objective]] = None
482        interval_objectives: typing.Optional[list[records.Objective]] = None
483        record_state: typedefs.IntAnd[records.RecordState]
484
485        record_state = records.RecordState(payload["state"])
486
487        if raw_objs := payload.get("objectives"):
488            objectives = [self.deserialize_objectives(obj) for obj in raw_objs]
489
490        if raw_interval_objs := payload.get("intervalObjectives"):
491            interval_objectives = [
492                self.deserialize_objectives(obj) for obj in raw_interval_objs
493            ]
494
495        return records.Record(
496            scores=scores,
497            categories_node_hash=nodes.get("categories_hash", undefined.UNDEFINED),
498            seals_node_hash=nodes.get("seals_hash", undefined.UNDEFINED),
499            state=record_state,
500            objectives=objectives,
501            interval_objectives=interval_objectives,
502            redeemed_count=payload.get("intervalsRedeemedCount", 0),
503            completion_times=payload.get("completedCount", None),
504            reward_visibility=payload.get("rewardVisibilty", None),
505        )

Deserialize a JSON object of a profile record component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON object payload
  • scores (typing.Optional[records.RecordScores]): The records scores object. This exists only to keep the signature of aiobungie.crates.CharacterRecord with the record object. As it will always be None in that object.
  • **nodes (int): An int kwargs use to grab the node hashes while deserializing components.
Returns
  • aiobungie.records.Record: A standard implementation of a profile record component.
def deserialize_character_records( self, payload: dict[str, typing.Any], scores: Optional[aiobungie.crates.records.RecordScores] = None, record_hashes: Optional[list[int]] = None) -> aiobungie.crates.records.CharacterRecord:
507    def deserialize_character_records(
508        self,
509        payload: typedefs.JSONObject,
510        scores: typing.Optional[records.RecordScores] = None,
511        record_hashes: typing.Optional[list[int]] = None,
512    ) -> records.CharacterRecord:
513
514        record = self.deserialize_records(payload, scores)
515        return records.CharacterRecord(
516            scores=scores,
517            categories_node_hash=record.categories_node_hash,
518            seals_node_hash=record.seals_node_hash,
519            state=record.state,
520            objectives=record.objectives,
521            interval_objectives=record.interval_objectives,
522            redeemed_count=payload.get("intervalsRedeemedCount", 0),
523            completion_times=payload.get("completedCount"),
524            reward_visibility=payload.get("rewardVisibilty"),
525            record_hashes=record_hashes or [],
526        )

Deserialize a JSON object of a profile character record component.

This almost does the same this as deserialize_records but has more fields which can only be found in a character record.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON object payload
Returns
  • aiobungie.records.CharacterRecord: A standard implementation of a profile character record component.
def deserialize_character_dye(self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.Dye:
528    def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye:
529        return character.Dye(
530            channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"]
531        )

Deserialize a JSON payload of a character's dye information.

Parameters
Returns
  • aiobungie.crates.character.Dye: Information about a character dye object.
def deserialize_character_customization( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.CustomizationOptions:
533    def deserialize_character_customization(
534        self, payload: typedefs.JSONObject
535    ) -> character.CustomizationOptions:
536        return character.CustomizationOptions(
537            personality=payload["personality"],
538            face=payload["face"],
539            skin_color=payload["skinColor"],
540            lip_color=payload["lipColor"],
541            eye_color=payload["eyeColor"],
542            hair_colors=payload.get("hairColors", []),
543            feature_colors=payload.get("featureColors", []),
544            decal_color=payload["decalColor"],
545            wear_helmet=payload["wearHelmet"],
546            hair_index=payload["hairIndex"],
547            feature_index=payload["featureIndex"],
548            decal_index=payload["decalIndex"],
549        )

Deserialize a JSON payload of a character customization information found in character render data profile component.

Parameters
Returns
  • aiobungie.crates.character.CustomizationOptions: Information about a character customs object.
def deserialize_character_minimal_equipments( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.MinimalEquipments:
551    def deserialize_character_minimal_equipments(
552        self, payload: typedefs.JSONObject
553    ) -> character.MinimalEquipments:
554        dyes = None
555        if raw_dyes := payload.get("dyes"):
556            if raw_dyes:
557                dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes]
558        return character.MinimalEquipments(
559            net=self._net, item_hash=payload["itemHash"], dyes=dyes
560        )

Deserialize a singular JSON peer view of equipment found in character render data profile component.

Parameters
Returns
  • aiobungie.crates.character.MinimalEquipments: A minimal equipment object.
def deserialize_character_render_data( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.character.RenderedData:
562    def deserialize_character_render_data(
563        self, payload: typedefs.JSONObject, /
564    ) -> character.RenderedData:
565        return character.RenderedData(
566            net=self._net,
567            customization=self.deserialize_character_customization(
568                payload["customization"]
569            ),
570            custom_dyes=[
571                self.deserialize_character_dye(dye)
572                for dye in payload["customDyes"]
573                if dye
574            ],
575            equipment=[
576                self.deserialize_character_minimal_equipments(equipment)
577                for equipment in payload["peerView"]["equipment"]
578            ],
579        )

Deserialize a JSON payload of a profile character render data component.

Parameters
Returns
def deserialize_available_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.AvailableActivity:
581    def deserialize_available_activity(
582        self, payload: typedefs.JSONObject
583    ) -> activity.AvailableActivity:
584        return activity.AvailableActivity(
585            hash=payload["activityHash"],
586            is_new=payload["isNew"],
587            is_completed=payload["isCompleted"],
588            is_visible=payload["isVisible"],
589            display_level=payload.get("displayLevel"),
590            recommended_light=payload.get("recommendedLight"),
591            difficulty=activity.Difficulty(payload["difficultyTier"]),
592            can_join=payload["canJoin"],
593            can_lead=payload["canLead"],
594        )

Deserialize a JSON payload of an available activities.

This method is used to deserialize an array of aiobungie.crates.CharacterActivity.available_activities.

Parameters
Returns
def deserialize_character_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.CharacterActivity:
596    def deserialize_character_activity(
597        self, payload: typedefs.JSONObject
598    ) -> activity.CharacterActivity:
599        current_mode: typing.Optional[enums.GameMode] = None
600        if raw_current_mode := payload.get("currentActivityModeType"):
601            current_mode = enums.GameMode(raw_current_mode)
602
603        current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None
604        if raw_current_modes := payload.get("currentActivityModeTypes"):
605            current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes]
606
607        return activity.CharacterActivity(
608            date_started=time.clean_date(payload["dateActivityStarted"]),
609            current_hash=payload["currentActivityHash"],
610            current_mode_hash=payload["currentActivityModeHash"],
611            current_mode=current_mode,
612            current_mode_hashes=payload.get("currentActivityModeHashes"),
613            current_mode_types=current_mode_types,
614            current_playlist_hash=payload.get("currentPlaylistActivityHash"),
615            last_story_hash=payload["lastCompletedStoryHash"],
616            available_activities=[
617                self.deserialize_available_activity(activity_)
618                for activity_ in payload["availableActivities"]
619            ],
620        )

Deserialize a JSON payload of character activity profile component.

Parameters
Returns
def deserialize_profile_items( self, payload: dict[str, typing.Any], /) -> list[aiobungie.crates.profile.ProfileItemImpl]:
622    def deserialize_profile_items(
623        self, payload: typedefs.JSONObject, /
624    ) -> list[profile.ProfileItemImpl]:
625        return [self.deserialize_profile_item(item) for item in payload["items"]]

Deserialize a JSON payload of profile items component information.

This may deserialize profileInventories or profileCurrencies or any other alternatives.

Parameters
Returns
def deserialize_progressions( self, payload: dict[str, typing.Any]) -> aiobungie.crates.progressions.Progression:
668    def deserialize_progressions(
669        self, payload: typedefs.JSONObject
670    ) -> progressions.Progression:
671        return progressions.Progression(
672            hash=int(payload["progressionHash"]),
673            level=int(payload["level"]),
674            cap=int(payload["levelCap"]),
675            daily_limit=int(payload["dailyLimit"]),
676            weekly_limit=int(payload["weeklyLimit"]),
677            current_progress=int(payload["currentProgress"]),
678            daily_progress=int(payload["dailyProgress"]),
679            needed=int(payload["progressToNextLevel"]),
680            next_level=int(payload["nextLevelAt"]),
681        )
def deserialize_milestone( self, payload: dict[str, typing.Any]) -> aiobungie.crates.milestones.Milestone:
769    def deserialize_milestone(
770        self, payload: typedefs.JSONObject
771    ) -> milestones.Milestone:
772        start_date: typing.Optional[datetime.datetime] = None
773        if raw_start_date := payload.get("startDate"):
774            start_date = time.clean_date(raw_start_date)
775
776        end_date: typing.Optional[datetime.datetime] = None
777        if raw_end_date := payload.get("endDate"):
778            end_date = time.clean_date(raw_end_date)
779
780        rewards: typing.Optional[
781            collections.Collection[milestones.MilestoneReward]
782        ] = None
783        if raw_rewards := payload.get("rewards"):
784            rewards = [
785                self._deserialize_milestone_rewards(reward) for reward in raw_rewards
786            ]
787
788        activities: typing.Optional[
789            collections.Sequence[milestones.MilestoneActivity]
790        ] = None
791        if raw_activities := payload.get("activities"):
792            activities = [
793                self._deserialize_milestone_activity(active)
794                for active in raw_activities
795            ]
796
797        quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None
798        if raw_quests := payload.get("availableQuests"):
799            quests = [
800                self._deserialize_milestone_available_quest(quest)
801                for quest in raw_quests
802            ]
803
804        vendors: typing.Optional[
805            collections.Sequence[milestones.MilestoneVendor]
806        ] = None
807        if raw_vendors := payload.get("vendors"):
808            vendors = [
809                milestones.MilestoneVendor(
810                    vendor_hash=vendor["vendorHash"],
811                    preview_itemhash=vendor.get("previewItemHash"),
812                )
813                for vendor in raw_vendors
814            ]
815
816        return milestones.Milestone(
817            hash=payload["milestoneHash"],
818            start_date=start_date,
819            end_date=end_date,
820            order=payload["order"],
821            rewards=rewards,
822            available_quests=quests,
823            activities=activities,
824            vendors=vendors,
825        )
def deserialize_characters( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.Character]:
842    def deserialize_characters(
843        self, payload: typedefs.JSONObject
844    ) -> collections.Mapping[int, character.Character]:
845        return {
846            int(char_id): self._set_character_attrs(char)
847            for char_id, char in payload["data"].items()
848        }
def deserialize_character( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.Character:
850    def deserialize_character(
851        self, payload: typedefs.JSONObject
852    ) -> character.Character:
853        return self._set_character_attrs(payload)
def deserialize_character_equipments( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, collections.abc.Sequence[aiobungie.crates.profile.ProfileItemImpl]]:
855    def deserialize_character_equipments(
856        self, payload: typedefs.JSONObject
857    ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]:
858        return {
859            int(char_id): self.deserialize_profile_items(item)
860            for char_id, item in payload["data"].items()
861        }
def deserialize_character_activities( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.activity.CharacterActivity]:
863    def deserialize_character_activities(
864        self, payload: typedefs.JSONObject
865    ) -> collections.Mapping[int, activity.CharacterActivity]:
866        return {
867            int(char_id): self.deserialize_character_activity(data)
868            for char_id, data in payload["data"].items()
869        }
def deserialize_characters_render_data( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.RenderedData]:
871    def deserialize_characters_render_data(
872        self, payload: typedefs.JSONObject
873    ) -> collections.Mapping[int, character.RenderedData]:
874        return {
875            int(char_id): self.deserialize_character_render_data(data)
876            for char_id, data in payload["data"].items()
877        }
def deserialize_character_progressions( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.CharacterProgression:
879    def deserialize_character_progressions(
880        self, payload: typedefs.JSONObject
881    ) -> character.CharacterProgression:
882        progressions_ = {
883            int(prog_id): self.deserialize_progressions(prog)
884            for prog_id, prog in payload["progressions"].items()
885        }
886
887        factions = {
888            int(faction_id): self._deserialize_factions(faction)
889            for faction_id, faction in payload["factions"].items()
890        }
891
892        milestones_ = {
893            int(milestone_hash): self.deserialize_milestone(milestone)
894            for milestone_hash, milestone in payload["milestones"].items()
895        }
896
897        uninstanced_item_objectives = {
898            int(item_hash): [self.deserialize_objectives(ins) for ins in obj]
899            for item_hash, obj in payload["uninstancedItemObjectives"].items()
900        }
901
902        artifact = payload["seasonalArtifact"]
903        seasonal_artifact = season.CharacterScopedArtifact(
904            hash=artifact["artifactHash"],
905            points_used=artifact["pointsUsed"],
906            reset_count=artifact["resetCount"],
907            tiers=[
908                self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"]
909            ],
910        )
911        checklists = payload["checklists"]
912
913        return character.CharacterProgression(
914            progressions=progressions_,
915            factions=factions,
916            checklists=checklists,
917            milestones=milestones_,
918            seasonal_artifact=seasonal_artifact,
919            uninstanced_item_objectives=uninstanced_item_objectives,
920        )
def deserialize_character_progressions_mapping( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.CharacterProgression]:
922    def deserialize_character_progressions_mapping(
923        self, payload: typedefs.JSONObject
924    ) -> collections.Mapping[int, character.CharacterProgression]:
925        character_progressions: collections.Mapping[
926            int, character.CharacterProgression
927        ] = {}
928        for char_id, data in payload["data"].items():
929            # A little hack to stop mypy complaining about Mapping <-> dict
930            character_progressions[int(char_id)] = self.deserialize_character_progressions(data)  # type: ignore[index]
931        return character_progressions
def deserialize_characters_records( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.records.CharacterRecord]:
933    def deserialize_characters_records(
934        self,
935        payload: typedefs.JSONObject,
936    ) -> collections.Mapping[int, records.CharacterRecord]:
937
938        return {
939            int(rec_id): self.deserialize_character_records(
940                rec, record_hashes=payload.get("featuredRecordHashes")
941            )
942            for rec_id, rec in payload["records"].items()
943        }
def deserialize_profile_records( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.records.Record]:
945    def deserialize_profile_records(
946        self, payload: typedefs.JSONObject
947    ) -> collections.Mapping[int, records.Record]:
948        raw_profile_records = payload["data"]
949        scores = records.RecordScores(
950            current_score=raw_profile_records["score"],
951            legacy_score=raw_profile_records["legacyScore"],
952            lifetime_score=raw_profile_records["lifetimeScore"],
953        )
954        return {
955            int(record_id): self.deserialize_records(
956                record,
957                scores,
958                categories_hash=raw_profile_records["recordCategoriesRootNodeHash"],
959                seals_hash=raw_profile_records["recordSealsRootNodeHash"],
960            )
961            for record_id, record in raw_profile_records["records"].items()
962        }
def deserialize_craftables_component( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.CraftablesComponent:
 999    def deserialize_craftables_component(
1000        self, payload: typedefs.JSONObject
1001    ) -> components.CraftablesComponent:
1002        return components.CraftablesComponent(
1003            net=self._net,
1004            craftables={
1005                int(item_id): self._deserialize_craftable_item(item)
1006                for item_id, item in payload["craftables"].items()
1007                if item is not None
1008            },
1009            crafting_root_node_hash=payload["craftingRootNodeHash"],
1010        )
def deserialize_components( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.Component:
1012    def deserialize_components(  # noqa: C901 Too complex.
1013        self, payload: typedefs.JSONObject
1014    ) -> components.Component:
1015
1016        profile_: typing.Optional[profile.Profile] = None
1017        if raw_profile := payload.get("profile"):
1018            profile_ = self.deserialize_profile(raw_profile)
1019
1020        profile_progression: typing.Optional[profile.ProfileProgression] = None
1021        if raw_profile_progression := payload.get("profileProgression"):
1022            profile_progression = self.deserialize_profile_progression(
1023                raw_profile_progression
1024            )
1025
1026        profile_currencies: typing.Optional[
1027            collections.Sequence[profile.ProfileItemImpl]
1028        ] = None
1029        if raw_profile_currencies := payload.get("profileCurrencies"):
1030            if "data" in raw_profile_currencies:
1031                profile_currencies = self.deserialize_profile_items(
1032                    raw_profile_currencies["data"]
1033                )
1034
1035        profile_inventories: typing.Optional[
1036            collections.Sequence[profile.ProfileItemImpl]
1037        ] = None
1038        if raw_profile_inventories := payload.get("profileInventory"):
1039            if "data" in raw_profile_inventories:
1040                profile_inventories = self.deserialize_profile_items(
1041                    raw_profile_inventories["data"]
1042                )
1043
1044        profile_records: typing.Optional[
1045            collections.Mapping[int, records.Record]
1046        ] = None
1047
1048        if raw_profile_records_ := payload.get("profileRecords"):
1049            profile_records = self.deserialize_profile_records(raw_profile_records_)
1050
1051        characters: typing.Optional[typing.Mapping[int, character.Character]] = None
1052        if raw_characters := payload.get("characters"):
1053            characters = self.deserialize_characters(raw_characters)
1054
1055        character_records: typing.Optional[
1056            collections.Mapping[int, records.CharacterRecord]
1057        ] = None
1058
1059        if raw_character_records := payload.get("characterRecords"):
1060            # Had to do it in two steps..
1061            to_update: typedefs.JSONObject = {}
1062            for _, data in raw_character_records["data"].items():
1063                for record_id, record in data.items():
1064                    to_update[record_id] = record
1065
1066            character_records = {
1067                int(rec_id): self.deserialize_character_records(
1068                    rec, record_hashes=to_update.get("featuredRecordHashes")
1069                )
1070                for rec_id, rec in to_update["records"].items()
1071            }
1072
1073        character_equipments: typing.Optional[
1074            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1075        ] = None
1076        if raw_character_equips := payload.get("characterEquipment"):
1077            character_equipments = self.deserialize_character_equipments(
1078                raw_character_equips
1079            )
1080
1081        character_inventories: typing.Optional[
1082            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1083        ] = None
1084        if raw_character_inventories := payload.get("characterInventories"):
1085            if "data" in raw_character_inventories:
1086                character_inventories = self.deserialize_character_equipments(
1087                    raw_character_inventories
1088                )
1089
1090        character_activities: typing.Optional[
1091            collections.Mapping[int, activity.CharacterActivity]
1092        ] = None
1093        if raw_char_acts := payload.get("characterActivities"):
1094            character_activities = self.deserialize_character_activities(raw_char_acts)
1095
1096        character_render_data: typing.Optional[
1097            collections.Mapping[int, character.RenderedData]
1098        ] = None
1099        if raw_character_render_data := payload.get("characterRenderData"):
1100            character_render_data = self.deserialize_characters_render_data(
1101                raw_character_render_data
1102            )
1103
1104        character_progressions: typing.Optional[
1105            collections.Mapping[int, character.CharacterProgression]
1106        ] = None
1107
1108        if raw_character_progressions := payload.get("characterProgressions"):
1109            character_progressions = self.deserialize_character_progressions_mapping(
1110                raw_character_progressions
1111            )
1112
1113        profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None
1114        if raw_profile_string_vars := payload.get("profileStringVariables"):
1115            profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"]
1116
1117        character_string_vars: typing.Optional[
1118            collections.Mapping[int, collections.Mapping[int, int]]
1119        ] = None
1120        if raw_character_string_vars := payload.get("characterStringVariables"):
1121            character_string_vars = {
1122                int(char_id): data["integerValuesByHash"]
1123                for char_id, data in raw_character_string_vars["data"].items()
1124            }
1125
1126        metrics: typing.Optional[
1127            collections.Sequence[
1128                collections.Mapping[
1129                    int, tuple[bool, typing.Optional[records.Objective]]
1130                ]
1131            ]
1132        ] = None
1133        root_node_hash: typing.Optional[int] = None
1134
1135        if raw_metrics := payload.get("metrics"):
1136            root_node_hash = raw_metrics["data"]["metricsRootNodeHash"]
1137            metrics = [
1138                {
1139                    int(metrics_hash): (
1140                        data["invisible"],
1141                        self.deserialize_objectives(data["objectiveProgress"])
1142                        if "objectiveProgress" in data
1143                        else None,
1144                    )
1145                    for metrics_hash, data in raw_metrics["data"]["metrics"].items()
1146                }
1147            ]
1148        transitory: typing.Optional[fireteams.FireteamParty] = None
1149        if raw_transitory := payload.get("profileTransitoryData"):
1150            if "data" in raw_transitory:
1151                transitory = self.deserialize_fireteam_party(raw_transitory["data"])
1152
1153        item_components: typing.Optional[components.ItemsComponent] = None
1154        if raw_item_components := payload.get("itemComponents"):
1155            item_components = self.deserialize_items_component(raw_item_components)
1156
1157        profile_plugsets: typing.Optional[
1158            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1159        ] = None
1160
1161        if raw_profile_plugs := payload.get("profilePlugSets"):
1162            profile_plugsets = {
1163                int(index): [self.deserialize_plug_item_state(state) for state in data]
1164                for index, data in raw_profile_plugs["data"]["plugs"].items()
1165            }
1166
1167        character_plugsets: typing.Optional[
1168            collections.Mapping[
1169                int, collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1170            ]
1171        ] = None
1172        if raw_char_plugsets := payload.get("characterPlugSets"):
1173            character_plugsets = {
1174                int(char_id): {
1175                    int(index): [
1176                        self.deserialize_plug_item_state(state) for state in data
1177                    ]
1178                    for index, data in inner["plugs"].items()
1179                }
1180                for char_id, inner in raw_char_plugsets["data"].items()
1181            }
1182
1183        character_collectibles: typing.Optional[
1184            collections.Mapping[int, items.Collectible]
1185        ] = None
1186        if raw_character_collectibles := payload.get("characterCollectibles"):
1187            character_collectibles = {
1188                int(char_id): self._deserialize_collectible(data)
1189                for char_id, data in raw_character_collectibles["data"].items()
1190            }
1191
1192        profile_collectibles: typing.Optional[items.Collectible] = None
1193        if raw_profile_collectibles := payload.get("profileCollectibles"):
1194            profile_collectibles = self._deserialize_collectible(
1195                raw_profile_collectibles["data"]
1196            )
1197
1198        profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1199        if raw_profile_nodes := payload.get("profilePresentationNodes"):
1200            profile_nodes = {
1201                int(node_hash): self._deserialize_node(node)
1202                for node_hash, node in raw_profile_nodes["data"]["nodes"].items()
1203            }
1204
1205        character_nodes: typing.Optional[
1206            collections.Mapping[int, collections.Mapping[int, records.Node]]
1207        ] = None
1208        if raw_character_nodes := payload.get("characterPresentationNodes"):
1209            character_nodes = {
1210                int(char_id): {
1211                    int(node_hash): self._deserialize_node(node)
1212                    for node_hash, node in each_character["nodes"].items()
1213                }
1214                for char_id, each_character in raw_character_nodes["data"].items()
1215            }
1216
1217        platform_silver: typing.Optional[
1218            collections.Mapping[str, profile.ProfileItemImpl]
1219        ] = None
1220        if raw_platform_silver := payload.get("platformSilver"):
1221            if "data" in raw_platform_silver:
1222                platform_silver = {
1223                    platform_name: self.deserialize_profile_item(item)
1224                    for platform_name, item in raw_platform_silver["data"][
1225                        "platformSilver"
1226                    ].items()
1227                }
1228
1229        character_currency_lookups: typing.Optional[
1230            collections.Mapping[int, collections.Sequence[items.Currency]]
1231        ] = None
1232        if raw_char_lookups := payload.get("characterCurrencyLookups"):
1233            if "data" in raw_char_lookups:
1234                character_currency_lookups = {
1235                    int(char_id): self._deserialize_currencies(currencie)
1236                    for char_id, currencie in raw_char_lookups["data"].items()
1237                }
1238
1239        character_craftables: typing.Optional[
1240            collections.Mapping[int, components.CraftablesComponent]
1241        ] = None
1242        if raw_character_craftables := payload.get("characterCraftables"):
1243
1244            if "data" in raw_character_craftables:
1245                character_craftables = {
1246                    int(char_id): self.deserialize_craftables_component(craftable)
1247                    for char_id, craftable in raw_character_craftables["data"].items()
1248                }
1249
1250        return components.Component(
1251            profiles=profile_,
1252            profile_progression=profile_progression,
1253            profile_currencies=profile_currencies,
1254            profile_inventories=profile_inventories,
1255            profile_records=profile_records,
1256            characters=characters,
1257            character_records=character_records,
1258            character_equipments=character_equipments,
1259            character_inventories=character_inventories,
1260            character_activities=character_activities,
1261            character_render_data=character_render_data,
1262            character_progressions=character_progressions,
1263            profile_string_variables=profile_string_vars,
1264            character_string_variables=character_string_vars,
1265            metrics=metrics,
1266            root_node_hash=root_node_hash,
1267            transitory=transitory,
1268            item_components=item_components,
1269            profile_plugsets=profile_plugsets,
1270            character_plugsets=character_plugsets,
1271            character_collectibles=character_collectibles,
1272            profile_collectibles=profile_collectibles,
1273            profile_nodes=profile_nodes,
1274            character_nodes=character_nodes,
1275            platform_silver=platform_silver,
1276            character_currency_lookups=character_currency_lookups,
1277            character_craftables=character_craftables,
1278        )

Deserialize a JSON payload of Bungie.net profile components information.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_items_component( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.ItemsComponent:
1280    def deserialize_items_component(
1281        self, payload: typedefs.JSONObject
1282    ) -> components.ItemsComponent:
1283        instances: typing.Optional[
1284            collections.Sequence[collections.Mapping[int, items.ItemInstance]]
1285        ] = None
1286        if raw_instances := payload.get("instances"):
1287            instances = [
1288                {
1289                    int(ins_id): self.deserialize_instanced_item(item)
1290                    for ins_id, item in raw_instances["data"].items()
1291                }
1292            ]
1293
1294        render_data: typing.Optional[
1295            collections.Mapping[int, tuple[bool, dict[int, int]]]
1296        ] = None
1297        if raw_render_data := payload.get("renderData"):
1298            render_data = {
1299                int(ins_id): (data["useCustomDyes"], data["artRegions"])
1300                for ins_id, data in raw_render_data["data"].items()
1301            }
1302
1303        stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None
1304        if raw_stats := payload.get("stats"):
1305            builder: collections.Mapping[int, items.ItemStatsView] = {}
1306            for ins_id, stat in raw_stats["data"].items():
1307                for _, items_ in stat.items():
1308                    builder[int(ins_id)] = self.deserialize_item_stats_view(items_)  # type: ignore[index]
1309            stats = builder
1310
1311        sockets: typing.Optional[
1312            collections.Mapping[int, collections.Sequence[items.ItemSocket]]
1313        ] = None
1314        if raw_sockets := payload.get("sockets"):
1315            sockets = {
1316                int(ins_id): [
1317                    self.deserialize_item_socket(socket) for socket in item["sockets"]
1318                ]
1319                for ins_id, item in raw_sockets["data"].items()
1320            }
1321
1322        objeectives: typing.Optional[
1323            collections.Mapping[int, collections.Sequence[records.Objective]]
1324        ] = None
1325        if raw_objectives := payload.get("objectives"):
1326            objeectives = {
1327                int(ins_id): [self.deserialize_objectives(objective)]
1328                for ins_id, data in raw_objectives["data"].items()
1329                for objective in data["objectives"]
1330            }
1331
1332        perks: typing.Optional[
1333            collections.Mapping[int, collections.Collection[items.ItemPerk]]
1334        ] = None
1335        if raw_perks := payload.get("perks"):
1336            perks = {
1337                int(ins_id): [
1338                    self.deserialize_item_perk(perk) for perk in item["perks"]
1339                ]
1340                for ins_id, item in raw_perks["data"].items()
1341            }
1342
1343        plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None
1344        if raw_plug_states := payload.get("plugStates"):
1345            pending_states: list[items.PlugItemState] = []
1346            for _, plug in raw_plug_states["data"].items():
1347                pending_states.append(self.deserialize_plug_item_state(plug))
1348            plug_states = pending_states
1349
1350        reusable_plugs: typing.Optional[
1351            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1352        ] = None
1353        if raw_re_plugs := payload.get("reusablePlugs"):
1354            reusable_plugs = {
1355                int(ins_id): [
1356                    self.deserialize_plug_item_state(state) for state in inner
1357                ]
1358                for ins_id, plug in raw_re_plugs["data"].items()
1359                for inner in list(plug["plugs"].values())
1360            }
1361
1362        plug_objectives: typing.Optional[
1363            collections.Mapping[
1364                int, collections.Mapping[int, collections.Collection[records.Objective]]
1365            ]
1366        ] = None
1367        if raw_plug_objectives := payload.get("plugObjectives"):
1368            plug_objectives = {
1369                int(ins_id): {
1370                    int(obj_hash): [self.deserialize_objectives(obj) for obj in objs]
1371                    for obj_hash, objs in inner["objectivesPerPlug"].items()
1372                }
1373                for ins_id, inner in raw_plug_objectives["data"].items()
1374            }
1375
1376        return components.ItemsComponent(
1377            sockets=sockets,
1378            stats=stats,
1379            render_data=render_data,
1380            instances=instances,
1381            objectives=objeectives,
1382            perks=perks,
1383            plug_states=plug_states,
1384            reusable_plugs=reusable_plugs,
1385            plug_objectives=plug_objectives,
1386        )

Deserialize a JSON objects within the itemComponents key.`

def deserialize_character_component( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.CharacterComponent:
1388    def deserialize_character_component(  # type: ignore[call-arg]
1389        self, payload: typedefs.JSONObject
1390    ) -> components.CharacterComponent:
1391
1392        character_: typing.Optional[character.Character] = None
1393        if raw_singuler_character := payload.get("character"):
1394            character_ = self.deserialize_character(raw_singuler_character["data"])
1395
1396        inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1397        if raw_inventory := payload.get("inventory"):
1398            if "data" in raw_inventory:
1399                inventory = self.deserialize_profile_items(raw_inventory["data"])
1400
1401        activities: typing.Optional[activity.CharacterActivity] = None
1402        if raw_activities := payload.get("activities"):
1403            activities = self.deserialize_character_activity(raw_activities["data"])
1404
1405        equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1406        if raw_equipments := payload.get("equipment"):
1407            equipment = self.deserialize_profile_items(raw_equipments["data"])
1408
1409        progressions_: typing.Optional[character.CharacterProgression] = None
1410        if raw_progressions := payload.get("progressions"):
1411            progressions_ = self.deserialize_character_progressions(
1412                raw_progressions["data"]
1413            )
1414
1415        render_data: typing.Optional[character.RenderedData] = None
1416        if raw_render_data := payload.get("renderData"):
1417            render_data = self.deserialize_character_render_data(
1418                raw_render_data["data"]
1419            )
1420
1421        character_records: typing.Optional[
1422            collections.Mapping[int, records.CharacterRecord]
1423        ] = None
1424        if raw_char_records := payload.get("records"):
1425            character_records = self.deserialize_characters_records(
1426                raw_char_records["data"]
1427            )
1428
1429        item_components: typing.Optional[components.ItemsComponent] = None
1430        if raw_item_components := payload.get("itemComponents"):
1431            item_components = self.deserialize_items_component(raw_item_components)
1432
1433        nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1434        if raw_nodes := payload.get("presentationNodes"):
1435            nodes = {
1436                int(node_hash): self._deserialize_node(node)
1437                for node_hash, node in raw_nodes["data"]["nodes"].items()
1438            }
1439
1440        collectibles: typing.Optional[items.Collectible] = None
1441        if raw_collectibles := payload.get("collectibles"):
1442            collectibles = self._deserialize_collectible(raw_collectibles["data"])
1443
1444        currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None
1445        if raw_currencies := payload.get("currencyLookups"):
1446            if "data" in raw_currencies:
1447                currency_lookups = self._deserialize_currencies(raw_currencies)
1448
1449        return components.CharacterComponent(
1450            activities=activities,
1451            equipment=equipment,
1452            inventory=inventory,
1453            progressions=progressions_,
1454            render_data=render_data,
1455            character=character_,
1456            character_records=character_records,
1457            profile_records=None,
1458            item_components=item_components,
1459            currency_lookups=currency_lookups,
1460            collectibles=collectibles,
1461            nodes=nodes,
1462        )

Deserialize a JSON payload of Destiny 2 character component.

Parameters
Returns
def deserialize_inventory_results( self, payload: dict[str, typing.Any]) -> aiobungie.Iterator[aiobungie.crates.entity.SearchableEntity]:
1490    def deserialize_inventory_results(
1491        self, payload: typedefs.JSONObject
1492    ) -> iterators.Iterator[entity.SearchableEntity]:
1493        suggested_words: list[str] = payload["suggestedWords"]
1494
1495        def _check_unknown(s: str) -> undefined.UndefinedOr[str]:
1496            return s if not typedefs.is_unknown(s) else undefined.UNDEFINED
1497
1498        return iterators.Iterator(
1499            [
1500                entity.SearchableEntity(
1501                    net=self._net,
1502                    hash=data["hash"],
1503                    entity_type=data["entityType"],
1504                    weight=data["weight"],
1505                    suggested_words=suggested_words,
1506                    name=data["displayProperties"]["name"],
1507                    has_icon=data["displayProperties"]["hasIcon"],
1508                    description=_check_unknown(
1509                        data["displayProperties"]["description"]
1510                    ),
1511                    icon=assets.Image(data["displayProperties"]["icon"]),
1512                )
1513                for data in payload["results"]["results"]
1514            ]
1515        )

Deserialize results of searched Destiny2 entities.

Parameters
Returns
def deserialize_inventory_entity( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.entity.InventoryEntity:
1544    def deserialize_inventory_entity(  # noqa: C901 Too complex.
1545        self, payload: typedefs.JSONObject, /
1546    ) -> entity.InventoryEntity:
1547
1548        props = self._set_entity_attrs(payload)
1549        objects = self._deserialize_inventory_item_objects(payload)
1550
1551        collectible_hash: typing.Optional[int] = None
1552        if raw_collectible_hash := payload.get("collectibleHash"):
1553            collectible_hash = int(raw_collectible_hash)
1554
1555        secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1556        if raw_second_icon := payload.get("secondaryIcon"):
1557            secondary_icon = assets.Image(raw_second_icon)
1558
1559        secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1560        if raw_second_overlay := payload.get("secondaryOverlay"):
1561            secondary_overlay = assets.Image(raw_second_overlay)
1562
1563        secondary_special: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1564        if raw_second_special := payload.get("secondarySpecial"):
1565            secondary_special = assets.Image(raw_second_special)
1566
1567        screenshot: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1568        if raw_screenshot := payload.get("screenshot"):
1569            screenshot = assets.Image(raw_screenshot)
1570
1571        watermark_icon: typing.Optional[assets.Image] = None
1572        if raw_watermark_icon := payload.get("iconWatermark"):
1573            watermark_icon = assets.Image(raw_watermark_icon)
1574
1575        watermark_shelved: typing.Optional[assets.Image] = None
1576        if raw_watermark_shelved := payload.get("iconWatermarkShelved"):
1577            watermark_shelved = assets.Image(raw_watermark_shelved)
1578
1579        about: undefined.UndefinedOr[str] = undefined.UNDEFINED
1580        if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown(
1581            raw_about
1582        ):
1583            about = raw_about
1584
1585        ui_item_style: undefined.UndefinedOr[str] = undefined.UNDEFINED
1586        if (
1587            raw_ui_style := payload.get("uiItemDisplayStyle")
1588        ) and not typedefs.is_unknown(raw_ui_style):
1589            ui_item_style = raw_ui_style
1590
1591        tier_and_name: undefined.UndefinedOr[str] = undefined.UNDEFINED
1592        if (
1593            raw_tier_and_name := payload.get("itemTypeAndTierDisplayName")
1594        ) and not typedefs.is_unknown(raw_tier_and_name):
1595            tier_and_name = raw_tier_and_name
1596
1597        type_name: undefined.UndefinedOr[str] = undefined.UNDEFINED
1598        if (
1599            raw_type_name := payload.get("itemTypeDisplayName")
1600        ) and not typedefs.is_unknown(raw_type_name):
1601            type_name = raw_type_name
1602
1603        display_source: undefined.UndefinedOr[str] = undefined.UNDEFINED
1604        if (
1605            raw_display_source := payload.get("displaySource")
1606        ) and not typedefs.is_unknown(raw_display_source):
1607            display_source = raw_display_source
1608
1609        lorehash: typing.Optional[int] = None
1610        if raw_lore_hash := payload.get("loreHash"):
1611            lorehash = int(raw_lore_hash)
1612
1613        summary_hash: typing.Optional[int] = None
1614        if raw_summary_hash := payload.get("summaryItemHash"):
1615            summary_hash = raw_summary_hash
1616
1617        breaker_type_hash: typing.Optional[int] = None
1618        if raw_breaker_type_hash := payload.get("breakerTypeHash"):
1619            breaker_type_hash = int(raw_breaker_type_hash)
1620
1621        damage_types: typing.Optional[collections.Sequence[int]] = None
1622        if raw_damage_types := payload.get("damageTypes"):
1623            damage_types = [int(type_) for type_ in raw_damage_types]
1624
1625        damagetype_hashes: typing.Optional[collections.Sequence[int]] = None
1626        if raw_damagetype_hashes := payload.get("damageTypeHashes"):
1627            damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes]
1628
1629        default_damagetype_hash: typing.Optional[int] = None
1630        if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"):
1631            default_damagetype_hash = int(raw_defaultdmg_hash)
1632
1633        emblem_objective_hash: typing.Optional[int] = None
1634        if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"):
1635            emblem_objective_hash = int(raw_emblem_obj_hash)
1636
1637        tier_type: typing.Optional[enums.TierType] = None
1638        tier: typing.Optional[enums.ItemTier] = None
1639        bucket_hash: typing.Optional[int] = None
1640        recovery_hash: typing.Optional[int] = None
1641        tier_name: undefined.UndefinedOr[str] = undefined.UNDEFINED
1642        isinstance_item: bool = False
1643        expire_tool_tip: undefined.UndefinedOr[str] = undefined.UNDEFINED
1644        expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.UNDEFINED
1645        suppress_expiration: bool = False
1646        max_stack_size: typing.Optional[int] = None
1647        stack_label: undefined.UndefinedOr[str] = undefined.UNDEFINED
1648
1649        if inventory := payload.get("inventory"):
1650            tier_type = enums.TierType(int(inventory["tierType"]))
1651            tier = enums.ItemTier(int(inventory["tierTypeHash"]))
1652            bucket_hash = int(inventory["bucketTypeHash"])
1653            recovery_hash = int(inventory["recoveryBucketTypeHash"])
1654            tier_name = inventory["tierTypeName"]
1655            isinstance_item = inventory["isInstanceItem"]
1656            suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"]
1657            max_stack_size = int(inventory["maxStackSize"])
1658
1659            try:
1660                stack_label = inventory["stackUniqueLabel"]
1661            except KeyError:
1662                pass
1663
1664        return entity.InventoryEntity(
1665            net=self._net,
1666            collectible_hash=collectible_hash,
1667            name=props.name,
1668            about=about,
1669            emblem_objective_hash=emblem_objective_hash,
1670            suppress_expiration=suppress_expiration,
1671            max_stack_size=max_stack_size,
1672            stack_label=stack_label,
1673            tier=tier,
1674            tier_type=tier_type,
1675            tier_name=tier_name,
1676            bucket_hash=bucket_hash,
1677            recovery_bucket_hash=recovery_hash,
1678            isinstance_item=isinstance_item,
1679            expire_in_orbit_message=expire_in_orbit_message,
1680            expiration_tooltip=expire_tool_tip,
1681            lore_hash=lorehash,
1682            type_and_tier_name=tier_and_name,
1683            summary_hash=summary_hash,
1684            ui_display_style=ui_item_style,
1685            type_name=type_name,
1686            breaker_type_hash=breaker_type_hash,
1687            description=props.description,
1688            display_source=display_source,
1689            hash=props.hash,
1690            damage_types=damage_types,
1691            index=props.index,
1692            icon=props.icon,
1693            has_icon=props.has_icon,
1694            screenshot=screenshot,
1695            watermark_icon=watermark_icon,
1696            watermark_shelved=watermark_shelved,
1697            secondary_icon=secondary_icon,
1698            secondary_overlay=secondary_overlay,
1699            secondary_special=secondary_special,
1700            type=enums.ItemType(int(payload["itemType"])),
1701            trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])],
1702            trait_ids=[trait for trait in payload.get("traitIds", [])],
1703            category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]],
1704            item_class=enums.Class(int(payload["classType"])),
1705            sub_type=enums.ItemSubType(int(payload["itemSubType"])),
1706            breaker_type=int(payload["breakerType"]),
1707            default_damagetype=int(payload["defaultDamageType"]),
1708            default_damagetype_hash=default_damagetype_hash,
1709            damagetype_hashes=damagetype_hashes,
1710            tooltip_notifications=payload["tooltipNotifications"],
1711            not_transferable=payload["nonTransferrable"],
1712            allow_actions=payload["allowActions"],
1713            is_equippable=payload["equippable"],
1714            objects=objects,
1715            background_colors=payload.get("backgroundColor", {}),
1716            season_hash=payload.get("seasonHash"),
1717            has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"],
1718        )

Deserialize a JSON payload of an inventory entity item information.

This can be any item from DestinyInventoryItemDefinition definition.

Parameters
Returns
def deserialize_objective_entity( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.entity.ObjectiveEntity:
1720    def deserialize_objective_entity(
1721        self, payload: typedefs.JSONObject, /
1722    ) -> entity.ObjectiveEntity:
1723        props = self._set_entity_attrs(payload)
1724        return entity.ObjectiveEntity(
1725            net=self._net,
1726            hash=props.hash,
1727            index=props.index,
1728            description=props.description,
1729            name=props.name,
1730            has_icon=props.has_icon,
1731            icon=props.icon,
1732            unlock_value_hash=payload["unlockValueHash"],
1733            completion_value=payload["completionValue"],
1734            scope=entity.GatingScope(int(payload["scope"])),
1735            location_hash=payload["locationHash"],
1736            allowed_negative_value=payload["allowNegativeValue"],
1737            allowed_value_change=payload["allowValueChangeWhenCompleted"],
1738            counting_downward=payload["isCountingDownward"],
1739            value_style=entity.ValueUIStyle(int(payload["valueStyle"])),
1740            progress_description=payload["progressDescription"],
1741            perks=payload["perks"],
1742            stats=payload["stats"],
1743            minimum_visibility=payload["minimumVisibilityThreshold"],
1744            allow_over_completion=payload["allowOvercompletion"],
1745            show_value_style=payload["showValueOnComplete"],
1746            display_only_objective=payload["isDisplayOnlyObjective"],
1747            complete_value_style=entity.ValueUIStyle(
1748                int(payload["completedValueStyle"])
1749            ),
1750            progress_value_style=entity.ValueUIStyle(
1751                int(payload["inProgressValueStyle"])
1752            ),
1753            ui_label=payload["uiLabel"],
1754            ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])),
1755        )

Deserialize a JSON payload of an objective entity information.

Parameters
Returns
def deserialize_activity( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.activity.Activity:
1783    def deserialize_activity(
1784        self,
1785        payload: typedefs.JSONObject,
1786        /,
1787    ) -> activity.Activity:
1788        period = time.clean_date(payload["period"])
1789        details = payload["activityDetails"]
1790        ref_id = int(details["referenceId"])
1791        instance_id = int(details["instanceId"])
1792        mode = enums.GameMode(details["mode"])
1793        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1794        is_private = details["isPrivate"]
1795        membership_type = enums.MembershipType(int(details["membershipType"]))
1796
1797        # Since we're using the same fields for post activity method
1798        # this check is required since post activity doesn't values values
1799        values = self._deserialize_activity_values(payload["values"])
1800
1801        return activity.Activity(
1802            net=self._net,
1803            hash=ref_id,
1804            instance_id=instance_id,
1805            mode=mode,
1806            modes=modes,
1807            is_private=is_private,
1808            membership_type=membership_type,
1809            occurred_at=period,
1810            values=values,
1811        )

Deserialize a JSON payload of an activity history information.

Parameters
Returns
def deserialize_activities( self, payload: dict[str, typing.Any]) -> aiobungie.Iterator[aiobungie.crates.activity.Activity]:
1813    def deserialize_activities(
1814        self, payload: typedefs.JSONObject
1815    ) -> iterators.Iterator[activity.Activity]:
1816        return iterators.Iterator(
1817            [
1818                self.deserialize_activity(activity_)
1819                for activity_ in payload["activities"]
1820            ]
1821        )

Deserialize a JSON payload of an array of activity history information.

Parameters
Returns
def deserialize_extended_weapon_values( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.ExtendedWeaponValues:
1823    def deserialize_extended_weapon_values(
1824        self, payload: typedefs.JSONObject
1825    ) -> activity.ExtendedWeaponValues:
1826
1827        assists: typing.Optional[int] = None
1828        if raw_assists := payload["values"].get("uniqueWeaponAssists"):
1829            assists = raw_assists["basic"]["value"]
1830        assists_damage: typing.Optional[int] = None
1831
1832        if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"):
1833            assists_damage = raw_assists_damage["basic"]["value"]
1834
1835        return activity.ExtendedWeaponValues(
1836            reference_id=int(payload["referenceId"]),
1837            kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"],
1838            precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][
1839                "value"
1840            ],
1841            assists=assists,
1842            assists_damage=assists_damage,
1843            precision_kills_percentage=(
1844                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"],
1845                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][
1846                    "displayValue"
1847                ],
1848            ),
1849        )

Deserialize values of extended weapons JSON object.

Parameters
Returns
def deserialize_post_activity_player( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.activity.PostActivityPlayer:
1872    def deserialize_post_activity_player(
1873        self, payload: typedefs.JSONObject, /
1874    ) -> activity.PostActivityPlayer:
1875        player = payload["player"]
1876
1877        class_hash: typedefs.NoneOr[int] = None
1878        if (class_hash := player.get("classHash")) is not None:
1879            class_hash = class_hash
1880
1881        race_hash: typedefs.NoneOr[int] = None
1882        if (race_hash := player.get("raceHash")) is not None:
1883            race_hash = race_hash
1884
1885        gender_hash: typedefs.NoneOr[int] = None
1886        if (gender_hash := player.get("genderHash")) is not None:
1887            gender_hash = gender_hash
1888
1889        character_class: undefined.UndefinedOr[str] = undefined.UNDEFINED
1890        if (
1891            character_class := player.get("characterClass")
1892        ) and not typedefs.is_unknown(character_class):
1893            character_class = character_class
1894
1895        character_level: typedefs.NoneOr[int] = None
1896        if (character_level := player.get("characterLevel")) is not None:
1897            character_level = character_level
1898
1899        return activity.PostActivityPlayer(
1900            standing=int(payload["standing"]),
1901            score=int(payload["score"]["basic"]["value"]),
1902            character_id=payload["characterId"],
1903            destiny_user=self.deserialize_destiny_membership(player["destinyUserInfo"]),
1904            character_class=character_class,
1905            character_level=character_level,
1906            race_hash=race_hash,
1907            gender_hash=gender_hash,
1908            class_hash=class_hash,
1909            light_level=int(player["lightLevel"]),
1910            emblem_hash=int(player["emblemHash"]),
1911            values=self._deserialize_activity_values(payload["values"]),
1912            extended_values=self._deserialize_extended_values(payload["extended"]),
1913        )

Deserialize a JSON payload of a post activity player information.

Parameters
Returns
def deserialize_post_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.PostActivity:
1925    def deserialize_post_activity(
1926        self, payload: typedefs.JSONObject
1927    ) -> activity.PostActivity:
1928        period = time.clean_date(payload["period"])
1929        details = payload["activityDetails"]
1930        ref_id = int(details["referenceId"])
1931        instance_id = int(details["instanceId"])
1932        mode = enums.GameMode(details["mode"])
1933        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1934        is_private = details["isPrivate"]
1935        membership_type = enums.MembershipType(int(details["membershipType"]))
1936        return activity.PostActivity(
1937            net=self._net,
1938            hash=ref_id,
1939            membership_type=membership_type,
1940            instance_id=instance_id,
1941            mode=mode,
1942            modes=modes,
1943            is_private=is_private,
1944            occurred_at=period,
1945            starting_phase=int(payload["startingPhaseIndex"]),
1946            players=[
1947                self.deserialize_post_activity_player(player)
1948                for player in payload["entries"]
1949            ],
1950            teams=[
1951                self._deserialize_post_activity_team(team) for team in payload["teams"]
1952            ],
1953        )

Deserialize a JSON payload of a post activity information.

Parameters
Returns
def deserialize_aggregated_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.AggregatedActivity:
1991    def deserialize_aggregated_activity(
1992        self, payload: typedefs.JSONObject
1993    ) -> activity.AggregatedActivity:
1994        return activity.AggregatedActivity(
1995            hash=int(payload["activityHash"]),
1996            values=self._deserialize_aggregated_activity_values(payload["values"]),
1997        )

Deserialize a JSON payload of an aggregated activity.

Parameters
Returns
def deserialize_aggregated_activities( self, payload: dict[str, typing.Any]) -> aiobungie.Iterator[aiobungie.crates.activity.AggregatedActivity]:
1999    def deserialize_aggregated_activities(
2000        self, payload: typedefs.JSONObject
2001    ) -> iterators.Iterator[activity.AggregatedActivity]:
2002        return iterators.Iterator(
2003            [
2004                self.deserialize_aggregated_activity(activity)
2005                for activity in payload["activities"]
2006            ]
2007        )

Deserialize a JSON payload of an array of aggregated activities.

Parameters
Returns
def deserialize_linked_profiles( self, payload: dict[str, typing.Any]) -> aiobungie.crates.profile.LinkedProfile:
2009    def deserialize_linked_profiles(
2010        self, payload: typedefs.JSONObject
2011    ) -> profile.LinkedProfile:
2012        bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"])
2013        error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2014        profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2015
2016        if raw_profile := payload.get("profiles"):
2017            for pfile in raw_profile:
2018                profiles_vec.append(self.deserialize_destiny_membership(pfile))
2019
2020        if raw_profiles_with_errors := payload.get("profilesWithErrors"):
2021            for raw_error_pfile in raw_profiles_with_errors:
2022                if error_pfile := raw_error_pfile.get("infoCard"):
2023                    error_profiles_vec.append(
2024                        self.deserialize_destiny_membership(error_pfile)
2025                    )
2026
2027        return profile.LinkedProfile(
2028            net=self._net,
2029            bungie=bungie_user,
2030            profiles=profiles_vec,
2031            profiles_with_errors=error_profiles_vec,
2032        )

Deserialize a JSON payload of Bungie.net hard linked profile information.

Parameters
Returns
def deserialize_clan_banners( self, payload: dict[str, typing.Any]) -> collections.abc.Sequence[aiobungie.crates.clans.ClanBanner]:
2034    def deserialize_clan_banners(
2035        self, payload: typedefs.JSONObject
2036    ) -> collections.Sequence[clans.ClanBanner]:
2037        banners_seq: typing.MutableSequence[clans.ClanBanner] = []
2038        if banners := payload.get("clanBannerDecals"):
2039            for k, v in banners.items():
2040                banner_obj = clans.ClanBanner(
2041                    id=int(k),
2042                    foreground=assets.Image(v["foregroundPath"]),
2043                    background=assets.Image(v["backgroundPath"]),
2044                )
2045                banners_seq.append(banner_obj)
2046        return banners_seq

Deserialize a JSON array of a clan banners information.

Parameters
Returns
def deserialize_public_milestone_content( self, payload: dict[str, typing.Any]) -> aiobungie.crates.milestones.MilestoneContent:
2048    def deserialize_public_milestone_content(
2049        self, payload: typedefs.JSONObject
2050    ) -> milestones.MilestoneContent:
2051        items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None
2052        if raw_categories := payload.get("itemCategories"):
2053            for item in raw_categories:
2054                title = undefined.UNDEFINED
2055                if raw_title := item.get("title"):
2056                    if raw_title != typedefs.Unknown:
2057                        title = raw_title
2058                if raw_hashes := item.get("itemHashes"):
2059                    hashes: collections.Sequence[int] = raw_hashes
2060
2061                items_categoris = milestones.MilestoneItems(title=title, hashes=hashes)
2062
2063        about = undefined.UNDEFINED
2064        if (raw_about := payload["about"]) != typedefs.Unknown:
2065            about = raw_about
2066
2067        status = undefined.UNDEFINED
2068        if (raw_status := payload["status"]) != typedefs.Unknown:
2069            status = raw_status
2070
2071        tips: typing.MutableSequence[undefined.UndefinedOr[str]] = []
2072        if raw_tips := payload.get("tips"):
2073            for raw_tip in raw_tips:
2074                if raw_tip == typedefs.Unknown:
2075                    raw_tip = undefined.UNDEFINED
2076                tips.append(raw_tip)
2077
2078        return milestones.MilestoneContent(
2079            about=about, status=status, tips=tips, items=items_categoris
2080        )

Deserialize a JSON payload of milestone content information.

Parameters
Returns
def deserialize_friend( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.friends.Friend:
2082    def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend:
2083        name = undefined.UNDEFINED
2084        if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown:
2085            name = raw_name
2086
2087        bungie_user: typedefs.NoneOr[user.BungieUser] = None
2088
2089        if raw_bungie_user := payload.get("bungieNetUser"):
2090            bungie_user = self.deserialize_bungie_user(raw_bungie_user)
2091
2092        return friends.Friend(
2093            net=self._net,
2094            id=int(payload["lastSeenAsMembershipId"]),
2095            name=name,
2096            code=payload.get("bungieGlobalDisplayNameCode"),
2097            relationship=enums.Relationship(payload["relationship"]),
2098            user=bungie_user,
2099            online_status=enums.Presence(payload["onlineStatus"]),
2100            online_title=payload["onlineTitle"],
2101            type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]),
2102        )

Deserialize a JSON payload of a Bungie friend information.

Parameters
Returns
def deserialize_friends( self, payload: dict[str, typing.Any]) -> collections.abc.Sequence[aiobungie.crates.friends.Friend]:
2104    def deserialize_friends(
2105        self, payload: typedefs.JSONObject
2106    ) -> collections.Sequence[friends.Friend]:
2107        mut_seq: typing.MutableSequence[friends.Friend] = []
2108        if raw_friends := payload.get("friends"):
2109            for friend in raw_friends:
2110                mut_seq.append(self.deserialize_friend(friend))
2111        return mut_seq

Deserialize a JSON sequence of Bungie friends information.

This is usually used to deserialize the incoming/outgoing friend requests.

Parameters
Returns
def deserialize_friend_requests( self, payload: dict[str, typing.Any]) -> aiobungie.crates.friends.FriendRequestView:
2113    def deserialize_friend_requests(
2114        self, payload: typedefs.JSONObject
2115    ) -> friends.FriendRequestView:
2116        incoming: typing.MutableSequence[friends.Friend] = []
2117        outgoing: typing.MutableSequence[friends.Friend] = []
2118
2119        if raw_incoming_requests := payload.get("incomingRequests"):
2120            for incoming_request in raw_incoming_requests:
2121                incoming.append(self.deserialize_friend(incoming_request))
2122
2123        if raw_outgoing_requests := payload.get("outgoingRequests"):
2124            for outgoing_request in raw_outgoing_requests:
2125                outgoing.append(self.deserialize_friend(outgoing_request))
2126
2127        return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)

Deserialize a JSON sequence of Bungie friend requests information.

This is used for incoming/outgoing friend requests.

Parameters
Returns
def deserialize_fireteams( self, payload: dict[str, typing.Any]) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]]:
2152    def deserialize_fireteams(
2153        self, payload: typedefs.JSONObject
2154    ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]:
2155        fireteams_: typing.MutableSequence[fireteams.Fireteam] = []
2156
2157        result: list[typedefs.JSONObject]
2158        if not (result := payload["results"]):
2159            return None
2160        for elem in result:
2161            fireteams_.append(
2162                self._set_fireteam_fields(
2163                    elem, total_results=int(payload["totalResults"])
2164                )
2165            )
2166        return fireteams_

Deserialize a JSON sequence of Bungie fireteams information.

Parameters
Returns
def deserialize_fireteam_destiny_users( self, payload: dict[str, typing.Any]) -> aiobungie.crates.fireteams.FireteamUser:
2168    def deserialize_fireteam_destiny_users(
2169        self, payload: typedefs.JSONObject
2170    ) -> fireteams.FireteamUser:
2171        destiny_obj = self.deserialize_destiny_membership(payload)
2172        # We could helpers.just return a DestinyMembership object but this is
2173        # missing the fireteam display name and id fields.
2174        return fireteams.FireteamUser(
2175            net=self._net,
2176            id=destiny_obj.id,
2177            code=destiny_obj.code,
2178            icon=destiny_obj.icon,
2179            types=destiny_obj.types,
2180            type=destiny_obj.type,
2181            is_public=destiny_obj.is_public,
2182            crossave_override=destiny_obj.crossave_override,
2183            name=destiny_obj.name,
2184            last_seen_name=destiny_obj.last_seen_name,
2185            fireteam_display_name=payload["FireteamDisplayName"],
2186            fireteam_membership_id=enums.MembershipType(
2187                payload["FireteamMembershipType"]
2188            ),
2189        )

Deserialize a JSON payload of Bungie fireteam destiny users information.

Parameters
Returns
def deserialize_fireteam_members( self, payload: dict[str, typing.Any], *, alternatives: bool = False) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.FireteamMember]]:
2191    def deserialize_fireteam_members(
2192        self, payload: typedefs.JSONObject, *, alternatives: bool = False
2193    ) -> typing.Optional[collections.Sequence[fireteams.FireteamMember]]:
2194        members_: list[fireteams.FireteamMember] = []
2195        if members := payload.get("Members" if not alternatives else "Alternates"):
2196            for member in members:
2197                bungie_fields = self.deserialize_partial_bungie_user(member)
2198                members_fields = fireteams.FireteamMember(
2199                    destiny_user=self.deserialize_fireteam_destiny_users(member),
2200                    has_microphone=member["hasMicrophone"],
2201                    character_id=int(member["characterId"]),
2202                    date_joined=time.clean_date(member["dateJoined"]),
2203                    last_platform_invite_date=time.clean_date(
2204                        member["lastPlatformInviteAttemptDate"]
2205                    ),
2206                    last_platform_invite_result=int(
2207                        member["lastPlatformInviteAttemptResult"]
2208                    ),
2209                    net=self._net,
2210                    name=bungie_fields.name,
2211                    id=bungie_fields.id,
2212                    icon=bungie_fields.icon,
2213                    is_public=bungie_fields.is_public,
2214                    crossave_override=bungie_fields.crossave_override,
2215                    types=bungie_fields.types,
2216                    type=bungie_fields.type,
2217                )
2218                members_.append(members_fields)
2219        else:
2220            return None
2221        return members_

Deserialize a JSON sequence of Bungie fireteam members information.

Parameters
  • payload (aiobungie.typedefs.JSONObject): The JSON payload.
  • alternatives (bool): If set to True, Then it will deserialize the alternatives data in the payload. If not the it will just deserialize the members data.
Returns
def deserialize_available_fireteams( self, data: dict[str, typing.Any], *, no_results: bool = False) -> Union[aiobungie.crates.fireteams.AvailableFireteam, collections.abc.Sequence[aiobungie.crates.fireteams.AvailableFireteam]]:
2223    def deserialize_available_fireteams(
2224        self,
2225        data: typedefs.JSONObject,
2226        *,
2227        no_results: bool = False,
2228    ) -> typing.Union[
2229        fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam]
2230    ]:
2231        fireteams_: list[fireteams.AvailableFireteam] = []
2232
2233        # This needs to be used outside the results
2234        # JSON key.
2235        if no_results is True:
2236            payload = data
2237
2238        if result := payload.get("results"):
2239
2240            for fireteam in result:
2241                found_fireteams = self._set_fireteam_fields(fireteam["Summary"])
2242                fireteams_fields = fireteams.AvailableFireteam(
2243                    id=found_fireteams.id,
2244                    group_id=found_fireteams.group_id,
2245                    platform=found_fireteams.platform,
2246                    activity_type=found_fireteams.activity_type,
2247                    is_immediate=found_fireteams.is_immediate,
2248                    is_public=found_fireteams.is_public,
2249                    is_valid=found_fireteams.is_valid,
2250                    owner_id=found_fireteams.owner_id,
2251                    player_slot_count=found_fireteams.player_slot_count,
2252                    available_player_slots=found_fireteams.available_player_slots,
2253                    available_alternate_slots=found_fireteams.available_alternate_slots,
2254                    title=found_fireteams.title,
2255                    date_created=found_fireteams.date_created,
2256                    locale=found_fireteams.locale,
2257                    last_modified=found_fireteams.last_modified,
2258                    total_results=found_fireteams.total_results,
2259                    members=self.deserialize_fireteam_members(payload),
2260                    alternatives=self.deserialize_fireteam_members(
2261                        payload, alternatives=True
2262                    ),
2263                )
2264            fireteams_.append(fireteams_fields)
2265            if no_results:
2266                return fireteams_fields
2267        return fireteams_

Deserialize a JSON payload of a sequence of/fireteam information.

Parameters
  • payload (aiobungie.typedefs.JSONObject): The JSON payload.
  • no_results (bool): Whether to deserialize the data from results in the payload or not.
Returns
  • typing.Union[aiobungie.crates.fireteams.AvailableFireteam, collections.Sequence[aiobungie.crates.fireteams.AvailableFireteam]] # noqa (E501): An available fireteam or a sequence of available fireteam.
def deserialize_fireteam_party( self, payload: dict[str, typing.Any]) -> aiobungie.crates.fireteams.FireteamParty:
2269    def deserialize_fireteam_party(
2270        self, payload: typedefs.JSONObject
2271    ) -> fireteams.FireteamParty:
2272        last_destination_hash: typing.Optional[int] = None
2273        if raw_dest_hash := payload.get("lastOrbitedDestinationHash"):
2274            last_destination_hash = int(raw_dest_hash)
2275
2276        return fireteams.FireteamParty(
2277            members=[
2278                self._deserialize_fireteam_party_member(member)
2279                for member in payload["partyMembers"]
2280            ],
2281            activity=self._deserialize_fireteam_party_current_activity(
2282                payload["currentActivity"]
2283            ),
2284            settings=self._deserialize_fireteam_party_settings(payload["joinability"]),
2285            last_destination_hash=last_destination_hash,
2286            tracking=payload["tracking"],
2287        )

Deserialize a JSON payload of profileTransitory component response.

Parameters
Returns
def deserialize_seasonal_artifact(self, payload: dict[str, typing.Any]) -> aiobungie.crates.season.Artifact:
2334    def deserialize_seasonal_artifact(
2335        self, payload: typedefs.JSONObject
2336    ) -> season.Artifact:
2337        if raw_artifact := payload.get("seasonalArtifact"):
2338            if points := raw_artifact.get("pointProgression"):
2339                points_prog = progressions.Progression(
2340                    hash=points["progressionHash"],
2341                    level=points["level"],
2342                    cap=points["levelCap"],
2343                    daily_limit=points["dailyLimit"],
2344                    weekly_limit=points["weeklyLimit"],
2345                    current_progress=points["currentProgress"],
2346                    daily_progress=points["dailyProgress"],
2347                    needed=points["progressToNextLevel"],
2348                    next_level=points["nextLevelAt"],
2349                )
2350
2351            if bonus := raw_artifact.get("powerBonusProgression"):
2352                power_bonus_prog = progressions.Progression(
2353                    hash=bonus["progressionHash"],
2354                    level=bonus["level"],
2355                    cap=bonus["levelCap"],
2356                    daily_limit=bonus["dailyLimit"],
2357                    weekly_limit=bonus["weeklyLimit"],
2358                    current_progress=bonus["currentProgress"],
2359                    daily_progress=bonus["dailyProgress"],
2360                    needed=bonus["progressToNextLevel"],
2361                    next_level=bonus["nextLevelAt"],
2362                )
2363            artifact = season.Artifact(
2364                net=self._net,
2365                hash=raw_artifact["artifactHash"],
2366                power_bonus=raw_artifact["powerBonus"],
2367                acquired_points=raw_artifact["pointsAcquired"],
2368                bonus=power_bonus_prog,
2369                points=points_prog,
2370            )
2371        return artifact

Deserialize a JSON payload of a Destiny 2 seasonal artifact information.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_profile_progression( self, payload: dict[str, typing.Any]) -> aiobungie.crates.profile.ProfileProgression:
2373    def deserialize_profile_progression(
2374        self, payload: typedefs.JSONObject
2375    ) -> profile.ProfileProgression:
2376        return profile.ProfileProgression(
2377            artifact=self.deserialize_seasonal_artifact(payload["data"]),
2378            checklist={
2379                int(check_id): checklists
2380                for check_id, checklists in payload["data"]["checklists"].items()
2381            },
2382        )

Deserialize a JSON payload of a profile progression component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_instanced_item( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemInstance:
2384    def deserialize_instanced_item(
2385        self, payload: typedefs.JSONObject
2386    ) -> items.ItemInstance:
2387        damage_type_hash: typing.Optional[int] = None
2388        if raw_damagetype_hash := payload.get("damageTypeHash"):
2389            damage_type_hash = int(raw_damagetype_hash)
2390
2391        required_hashes: typing.Optional[collections.Collection[int]] = None
2392        if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"):
2393            required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes]
2394
2395        breaker_type: typing.Optional[items.ItemBreakerType] = None
2396        if raw_break_type := payload.get("breakerType"):
2397            breaker_type = items.ItemBreakerType(int(raw_break_type))
2398
2399        breaker_type_hash: typing.Optional[int] = None
2400        if raw_break_type_hash := payload.get("breakerTypeHash"):
2401            breaker_type_hash = int(raw_break_type_hash)
2402
2403        energy: typing.Optional[items.ItemEnergy] = None
2404        if raw_energy := payload.get("energy"):
2405            energy = self.deserialize_item_energy(raw_energy)
2406
2407        primary_stats = None
2408        if raw_primary_stats := payload.get("primaryStat"):
2409            primary_stats = self.deserialize_item_stats_view(raw_primary_stats)
2410
2411        return items.ItemInstance(
2412            damage_type=enums.DamageType(int(payload["damageType"])),
2413            damage_type_hash=damage_type_hash,
2414            primary_stat=primary_stats,
2415            item_level=int(payload["itemLevel"]),
2416            quality=int(payload["quality"]),
2417            is_equipped=payload["isEquipped"],
2418            can_equip=payload["canEquip"],
2419            equip_required_level=int(payload["equipRequiredLevel"]),
2420            required_equip_unlock_hashes=required_hashes,
2421            cant_equip_reason=int(payload["cannotEquipReason"]),
2422            breaker_type=breaker_type,
2423            breaker_type_hash=breaker_type_hash,
2424            energy=energy,
2425        )

Deserialize a JSON object into an instanced item.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_item_energy( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemEnergy:
2427    def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy:
2428        energy_hash: typing.Optional[int] = None
2429        if raw_energy_hash := payload.get("energyTypeHash"):
2430            energy_hash = int(raw_energy_hash)
2431
2432        return items.ItemEnergy(
2433            hash=energy_hash,
2434            type=items.ItemEnergyType(int(payload["energyType"])),
2435            capacity=int(payload["energyCapacity"]),
2436            used_energy=int(payload["energyUsed"]),
2437            unused_energy=int(payload["energyUnused"]),
2438        )
def deserialize_item_perk(self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemPerk:
2440    def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk:
2441        perk_hash: typing.Optional[int] = None
2442        if raw_perk_hash := payload.get("perkHash"):
2443            perk_hash = int(raw_perk_hash)
2444
2445        return items.ItemPerk(
2446            hash=perk_hash,
2447            icon=assets.Image(payload["iconPath"]),
2448            is_active=payload["isActive"],
2449            is_visible=payload["visible"],
2450        )
def deserialize_item_socket( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemSocket:
2452    def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket:
2453        plug_hash: typing.Optional[int] = None
2454        if raw_plug_hash := payload.get("plugHash"):
2455            plug_hash = int(raw_plug_hash)
2456
2457        enable_fail_indexes: typing.Optional[list[int]] = None
2458        if raw_indexes := payload.get("enableFailIndexes"):
2459            enable_fail_indexes = [int(index) for index in raw_indexes]
2460
2461        return items.ItemSocket(
2462            plug_hash=plug_hash,
2463            is_enabled=payload["isEnabled"],
2464            enable_fail_indexes=enable_fail_indexes,
2465            is_visible=payload.get("visible"),
2466        )
def deserialize_item_stats_view( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemStatsView:
2468    def deserialize_item_stats_view(
2469        self, payload: typedefs.JSONObject
2470    ) -> items.ItemStatsView:
2471        return items.ItemStatsView(
2472            stat_hash=payload.get("statHash"), value=payload.get("value")
2473        )
def deserialize_plug_item_state( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.PlugItemState:
2475    def deserialize_plug_item_state(
2476        self, payload: typedefs.JSONObject
2477    ) -> items.PlugItemState:
2478        item_hash: typing.Optional[int] = None
2479        if raw_item_hash := payload.get("plugItemHash"):
2480            item_hash = int(raw_item_hash)
2481
2482        insert_fail_indexes: typedefs.NoneOr[list[int]] = None
2483        if raw_fail_indexes := payload.get("insertFailIndexes"):
2484            insert_fail_indexes = [int(k) for k in raw_fail_indexes]
2485
2486        enable_fail_indexes: typedefs.NoneOr[list[int]] = None
2487        if raw_enabled_indexes := payload.get("enableFailIndexes"):
2488            enable_fail_indexes = [int(k) for k in raw_enabled_indexes]
2489
2490        return items.PlugItemState(
2491            item_hash=item_hash,
2492            insert_fail_indexes=insert_fail_indexes,
2493            enable_fail_indexes=enable_fail_indexes,
2494            is_enabled=payload["enabled"],
2495            can_insert=payload["canInsert"],
2496        )
@typing.final
class FireteamActivity(builtins.int, aiobungie.Enum):
 67@typing.final
 68class FireteamActivity(int, enums.Enum):
 69    """An enum for the fireteam activities."""
 70
 71    ALL = 0
 72    CRUCIBLE = 2
 73    TRIALS_OF_OSIRIS = 3
 74    NIGHTFALL = 4
 75    ANY = 5
 76    GAMBIT = 6
 77    BLIND_WELL = 7
 78    NIGHTMARE_HUNTS = 12
 79    ALTARS_OF_SORROWS = 14
 80    DUNGEON = 15
 81    RAID_LW = 20
 82    RAID_GOS = 21
 83    RAID_DSC = 22
 84    EXO_CHALLENGE = 23
 85    S12_WRATHBORN = 24
 86    EMPIRE_HUNTS = 25
 87    S13_BATTLEGROUNDS = 26
 88    EXOTIC_QUEST = 27
 89    RAID_VOG = 28
 90    S14_EXPUNGE = 30
 91    S15_ASTRAL_ALIGNMENT = 31
 92    S15_SHATTERED_RELAM = 32
 93    SHATTERED_THRONE = 33
 94    PROPHECY = 34
 95    PIT_OF_HERESY = 35
 96    DOE = 36
 97    """Dares of Eternity."""
 98    DUNGEON_GOA = 37
 99    """Grasp of Avarice."""
100    VOW_OF_THE_DISCPILE = 38
101    CAMPAIGN = 39
102    WELLSPRING = 40
103    S16_BATTLEGROUNDS = 41
104    S17_NIGHTMARE_CONTAINMENT = 44
105    S17_SEVER = 45

An enum for the fireteam activities.

CRUCIBLE = <FireteamActivity.CRUCIBLE: 2>
TRIALS_OF_OSIRIS = <FireteamActivity.TRIALS_OF_OSIRIS: 3>
NIGHTFALL = <FireteamActivity.NIGHTFALL: 4>
GAMBIT = <FireteamActivity.GAMBIT: 6>
BLIND_WELL = <FireteamActivity.BLIND_WELL: 7>
NIGHTMARE_HUNTS = <FireteamActivity.NIGHTMARE_HUNTS: 12>
ALTARS_OF_SORROWS = <FireteamActivity.ALTARS_OF_SORROWS: 14>
DUNGEON = <FireteamActivity.DUNGEON: 15>
RAID_LW = <FireteamActivity.RAID_LW: 20>
RAID_GOS = <FireteamActivity.RAID_GOS: 21>
RAID_DSC = <FireteamActivity.RAID_DSC: 22>
EXO_CHALLENGE = <FireteamActivity.EXO_CHALLENGE: 23>
S12_WRATHBORN = <FireteamActivity.S12_WRATHBORN: 24>
EMPIRE_HUNTS = <FireteamActivity.EMPIRE_HUNTS: 25>
S13_BATTLEGROUNDS = <FireteamActivity.S13_BATTLEGROUNDS: 26>
EXOTIC_QUEST = <FireteamActivity.EXOTIC_QUEST: 27>
RAID_VOG = <FireteamActivity.RAID_VOG: 28>
S14_EXPUNGE = <FireteamActivity.S14_EXPUNGE: 30>
S15_ASTRAL_ALIGNMENT = <FireteamActivity.S15_ASTRAL_ALIGNMENT: 31>
S15_SHATTERED_RELAM = <FireteamActivity.S15_SHATTERED_RELAM: 32>
SHATTERED_THRONE = <FireteamActivity.SHATTERED_THRONE: 33>
PROPHECY = <FireteamActivity.PROPHECY: 34>
PIT_OF_HERESY = <FireteamActivity.PIT_OF_HERESY: 35>
DOE = <FireteamActivity.DOE: 36>

Dares of Eternity.

DUNGEON_GOA = <FireteamActivity.DUNGEON_GOA: 37>

Grasp of Avarice.

VOW_OF_THE_DISCPILE = <FireteamActivity.VOW_OF_THE_DISCPILE: 38>
CAMPAIGN = <FireteamActivity.CAMPAIGN: 39>
WELLSPRING = <FireteamActivity.WELLSPRING: 40>
S16_BATTLEGROUNDS = <FireteamActivity.S16_BATTLEGROUNDS: 41>
S17_NIGHTMARE_CONTAINMENT = <FireteamActivity.S17_NIGHTMARE_CONTAINMENT: 44>
S17_SEVER = <FireteamActivity.S17_SEVER: 45>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class FireteamDate(builtins.int, aiobungie.Enum):
131@typing.final
132class FireteamDate(int, enums.Enum):
133    """An enum for fireteam date ranges."""
134
135    ALL = 0
136    NOW = 1
137    TODAY = 2
138    TWO_DAYS = 3
139    THIS_WEEK = 4

An enum for fireteam date ranges.

ALL = <FireteamDate.ALL: 0>
NOW = <FireteamDate.NOW: 1>
TODAY = <FireteamDate.TODAY: 2>
TWO_DAYS = <FireteamDate.TWO_DAYS: 3>
THIS_WEEK = <FireteamDate.THIS_WEEK: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class FireteamLanguage(builtins.str, aiobungie.Enum):
108@typing.final
109class FireteamLanguage(str, enums.Enum):
110    """An enum for fireteams languages filters."""
111
112    ALL = ""
113    ENGLISH = "en"
114    FRENCH = "fr"
115    ESPANOL = "es"
116    DEUTSCH = "de"
117    ITALIAN = "it"
118    JAPANESE = "ja"
119    PORTUGUESE = "pt-br"
120    RUSSIAN = "ru"
121    POLISH = "pl"
122    KOREAN = "ko"
123    # ? China
124    ZH_CHT = "zh-cht"
125    ZH_CHS = "zh-chs"
126
127    def __str__(self) -> str:
128        return str(self.value)

An enum for fireteams languages filters.

ENGLISH = <FireteamLanguage.ENGLISH: en>
FRENCH = <FireteamLanguage.FRENCH: fr>
ESPANOL = <FireteamLanguage.ESPANOL: es>
DEUTSCH = <FireteamLanguage.DEUTSCH: de>
ITALIAN = <FireteamLanguage.ITALIAN: it>
JAPANESE = <FireteamLanguage.JAPANESE: ja>
PORTUGUESE = <FireteamLanguage.PORTUGUESE: pt-br>
RUSSIAN = <FireteamLanguage.RUSSIAN: ru>
POLISH = <FireteamLanguage.POLISH: pl>
KOREAN = <FireteamLanguage.KOREAN: ko>
ZH_CHT = <FireteamLanguage.ZH_CHT: zh-cht>
ZH_CHS = <FireteamLanguage.ZH_CHS: zh-chs>
Inherited Members
Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
@typing.final
class FireteamPlatform(builtins.int, aiobungie.Enum):
54@typing.final
55class FireteamPlatform(int, enums.Enum):
56    """An enum for fireteam related to bungie fireteams.
57    This is different from the normal `aiobungie.MembershipType`.
58    """
59
60    ANY = 0
61    PSN_NETWORK = 1
62    XBOX_LIVE = 2
63    STEAM = 4
64    STADIA = 5

An enum for fireteam related to bungie fireteams. This is different from the normal aiobungie.MembershipType.

PSN_NETWORK = <FireteamPlatform.PSN_NETWORK: 1>
XBOX_LIVE = <FireteamPlatform.XBOX_LIVE: 2>
STEAM = <FireteamPlatform.STEAM: 4>
STADIA = <FireteamPlatform.STADIA: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class Flag(enum.Flag):
 97class Flag(__enum.Flag):
 98    """Builtin Python enum flag with extra handlings."""
 99
100    # Needs to type this here for mypy
101    _value_: int
102
103    @property
104    def name(self) -> str:  # type: ignore[override]
105        if self._name_ is None:
106            self._name_ = f"UNKNOWN {self._value_}"
107
108        return self._name_
109
110    @property
111    def value(self) -> int:  # type: ignore[override]
112        return self._value_
113
114    def __str__(self) -> str:
115        return self.name
116
117    def __repr__(self) -> str:
118        return f"<{type(self).__name__}.{self.name}: {self._value_!s}>"
119
120    def __int__(self) -> int:
121        if isinstance(self.value, _ITERABLE):
122            raise TypeError(
123                f"Can't overload {self.value} in {type(self).__name__}, Please use `.value` attribute.",
124            )
125        return int(self.value)
126
127    def __or__(self, other: typing.Union[Flag, int]) -> Flag:
128        return self.__class__(self._value_ | int(other))
129
130    def __xor__(self, other: typing.Union[Flag, int]) -> Flag:
131        return self.__class__(self._value_ ^ int(other))
132
133    def __and__(self, other: typing.Union[Flag, int]) -> Flag:
134        return self.__class__(other & int(other))
135
136    def __invert__(self) -> Flag:
137        return self.__class__(~self._value_)
138
139    def __contains__(self, other: typing.Union[Flag, int]) -> bool:
140        return self.value & int(other) == int(other)

Builtin Python enum flag with extra handlings.

name: str

The name of the Enum member.

value: int

The value of the Enum member.

@attrs.define(auto_exc=True)
class Forbidden(aiobungie.HTTPException):
137@attrs.define(auto_exc=True)
138class Forbidden(HTTPException):
139    """Exception that's raised for when status code 403 occurs."""
140
141    http_status: http.HTTPStatus = attrs.field(
142        default=http.HTTPStatus.FORBIDDEN, init=False
143    )

Exception that's raised for when status code 403 occurs.

Forbidden( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class Forbidden.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
@typing.final
class GameMode(builtins.int, aiobungie.Enum):
269@typing.final
270class GameMode(int, Enum):
271    """An Enum for all available gamemodes in Destiny 2."""
272
273    NONE = 0
274    STORY = 2
275    STRIKE = 3
276    RAID = 4
277    ALLPVP = 5
278    PATROL = 6
279    ALLPVE = 7
280    RESERVED9 = 9
281    CONTROL = 10
282    RESERVED11 = 11
283    CLASH = 12
284    RESERVED13 = 13
285    CRIMSONDOUBLES = 15
286    NIGHTFALL = 16
287    HEROICNIGHTFALL = 17
288    ALLSTRIKES = 18
289    IRONBANNER = 19
290    RESERVED20 = 20
291    RESERVED21 = 21
292    RESERVED22 = 22
293    RESERVED24 = 24
294    ALLMAYHEM = 25
295    RESERVED26 = 26
296    RESERVED27 = 27
297    RESERVED28 = 28
298    RESERVED29 = 29
299    RESERVED30 = 30
300    SUPREMACY = 31
301    PRIVATEMATCHESALL = 32
302    SURVIVAL = 37
303    COUNTDOWN = 38
304    TRIALSOFTHENINE = 39
305    SOCIAL = 40
306    TRIALSCOUNTDOWN = 41
307    TRIALSSURVIVAL = 42
308    IRONBANNERCONTROL = 43
309    IRONBANNERCLASH = 44
310    IRONBANNERSUPREMACY = 45
311    SCOREDNIGHTFALL = 46
312    SCOREDHEROICNIGHTFALL = 47
313    RUMBLE = 48
314    ALLDOUBLES = 49
315    DOUBLES = 50
316    PRIVATEMATCHESCLASH = 51
317    PRIVATEMATCHESCONTROL = 52
318    PRIVATEMATCHESSUPREMACY = 53
319    PRIVATEMATCHESCOUNTDOWN = 54
320    PRIVATEMATCHESSURVIVAL = 55
321    PRIVATEMATCHESMAYHEM = 56
322    PRIVATEMATCHESRUMBLE = 57
323    HEROICADVENTURE = 58
324    SHOWDOWN = 59
325    LOCKDOWN = 60
326    SCORCHED = 61
327    SCORCHEDTEAM = 62
328    GAMBIT = 63
329    ALLPVECOMPETITIVE = 64
330    BREAKTHROUGH = 65
331    BLACKARMORYRUN = 66
332    SALVAGE = 67
333    IRONBANNERSALVAGE = 68
334    PVPCOMPETITIVE = 69
335    PVPQUICKPLAY = 70
336    CLASHQUICKPLAY = 71
337    CLASHCOMPETITIVE = 72
338    CONTROLQUICKPLAY = 73
339    CONTROLCOMPETITIVE = 74
340    GAMBITPRIME = 75
341    RECKONING = 76
342    MENAGERIE = 77
343    VEXOFFENSIVE = 78
344    NIGHTMAREHUNT = 79
345    ELIMINATION = 80
346    MOMENTUM = 81
347    DUNGEON = 82
348    SUNDIAL = 83
349    TRIALS_OF_OSIRIS = 84
350    DARES = 85
351    OFFENSIVE = 86
352    LOSTSECTOR = 87
353    RIFT = 88
354    ZONECONTROL = 89
355    IRONBANNERRIFT = 90

An Enum for all available gamemodes in Destiny 2.

NONE = <GameMode.NONE: 0>
STORY = <GameMode.STORY: 2>
STRIKE = <GameMode.STRIKE: 3>
RAID = <GameMode.RAID: 4>
ALLPVP = <GameMode.ALLPVP: 5>
PATROL = <GameMode.PATROL: 6>
ALLPVE = <GameMode.ALLPVE: 7>
RESERVED9 = <GameMode.RESERVED9: 9>
CONTROL = <GameMode.CONTROL: 10>
RESERVED11 = <GameMode.RESERVED11: 11>
CLASH = <GameMode.CLASH: 12>
RESERVED13 = <GameMode.RESERVED13: 13>
CRIMSONDOUBLES = <GameMode.CRIMSONDOUBLES: 15>
NIGHTFALL = <GameMode.NIGHTFALL: 16>
HEROICNIGHTFALL = <GameMode.HEROICNIGHTFALL: 17>
ALLSTRIKES = <GameMode.ALLSTRIKES: 18>
IRONBANNER = <GameMode.IRONBANNER: 19>
RESERVED20 = <GameMode.RESERVED20: 20>
RESERVED21 = <GameMode.RESERVED21: 21>
RESERVED22 = <GameMode.RESERVED22: 22>
RESERVED24 = <GameMode.RESERVED24: 24>
ALLMAYHEM = <GameMode.ALLMAYHEM: 25>
RESERVED26 = <GameMode.RESERVED26: 26>
RESERVED27 = <GameMode.RESERVED27: 27>
RESERVED28 = <GameMode.RESERVED28: 28>
RESERVED29 = <GameMode.RESERVED29: 29>
RESERVED30 = <GameMode.RESERVED30: 30>
SUPREMACY = <GameMode.SUPREMACY: 31>
PRIVATEMATCHESALL = <GameMode.PRIVATEMATCHESALL: 32>
SURVIVAL = <GameMode.SURVIVAL: 37>
COUNTDOWN = <GameMode.COUNTDOWN: 38>
TRIALSOFTHENINE = <GameMode.TRIALSOFTHENINE: 39>
SOCIAL = <GameMode.SOCIAL: 40>
TRIALSCOUNTDOWN = <GameMode.TRIALSCOUNTDOWN: 41>
TRIALSSURVIVAL = <GameMode.TRIALSSURVIVAL: 42>
IRONBANNERCONTROL = <GameMode.IRONBANNERCONTROL: 43>
IRONBANNERCLASH = <GameMode.IRONBANNERCLASH: 44>
IRONBANNERSUPREMACY = <GameMode.IRONBANNERSUPREMACY: 45>
SCOREDNIGHTFALL = <GameMode.SCOREDNIGHTFALL: 46>
SCOREDHEROICNIGHTFALL = <GameMode.SCOREDHEROICNIGHTFALL: 47>
RUMBLE = <GameMode.RUMBLE: 48>
ALLDOUBLES = <GameMode.ALLDOUBLES: 49>
DOUBLES = <GameMode.DOUBLES: 50>
PRIVATEMATCHESCLASH = <GameMode.PRIVATEMATCHESCLASH: 51>
PRIVATEMATCHESCONTROL = <GameMode.PRIVATEMATCHESCONTROL: 52>
PRIVATEMATCHESSUPREMACY = <GameMode.PRIVATEMATCHESSUPREMACY: 53>
PRIVATEMATCHESCOUNTDOWN = <GameMode.PRIVATEMATCHESCOUNTDOWN: 54>
PRIVATEMATCHESSURVIVAL = <GameMode.PRIVATEMATCHESSURVIVAL: 55>
PRIVATEMATCHESMAYHEM = <GameMode.PRIVATEMATCHESMAYHEM: 56>
PRIVATEMATCHESRUMBLE = <GameMode.PRIVATEMATCHESRUMBLE: 57>
HEROICADVENTURE = <GameMode.HEROICADVENTURE: 58>
SHOWDOWN = <GameMode.SHOWDOWN: 59>
LOCKDOWN = <GameMode.LOCKDOWN: 60>
SCORCHED = <GameMode.SCORCHED: 61>
SCORCHEDTEAM = <GameMode.SCORCHEDTEAM: 62>
GAMBIT = <GameMode.GAMBIT: 63>
ALLPVECOMPETITIVE = <GameMode.ALLPVECOMPETITIVE: 64>
BREAKTHROUGH = <GameMode.BREAKTHROUGH: 65>
BLACKARMORYRUN = <GameMode.BLACKARMORYRUN: 66>
SALVAGE = <GameMode.SALVAGE: 67>
IRONBANNERSALVAGE = <GameMode.IRONBANNERSALVAGE: 68>
PVPCOMPETITIVE = <GameMode.PVPCOMPETITIVE: 69>
PVPQUICKPLAY = <GameMode.PVPQUICKPLAY: 70>
CLASHQUICKPLAY = <GameMode.CLASHQUICKPLAY: 71>
CLASHCOMPETITIVE = <GameMode.CLASHCOMPETITIVE: 72>
CONTROLQUICKPLAY = <GameMode.CONTROLQUICKPLAY: 73>
CONTROLCOMPETITIVE = <GameMode.CONTROLCOMPETITIVE: 74>
GAMBITPRIME = <GameMode.GAMBITPRIME: 75>
RECKONING = <GameMode.RECKONING: 76>
MENAGERIE = <GameMode.MENAGERIE: 77>
VEXOFFENSIVE = <GameMode.VEXOFFENSIVE: 78>
NIGHTMAREHUNT = <GameMode.NIGHTMAREHUNT: 79>
ELIMINATION = <GameMode.ELIMINATION: 80>
MOMENTUM = <GameMode.MOMENTUM: 81>
DUNGEON = <GameMode.DUNGEON: 82>
SUNDIAL = <GameMode.SUNDIAL: 83>
TRIALS_OF_OSIRIS = <GameMode.TRIALS_OF_OSIRIS: 84>
DARES = <GameMode.DARES: 85>
OFFENSIVE = <GameMode.OFFENSIVE: 86>
LOSTSECTOR = <GameMode.LOSTSECTOR: 87>
RIFT = <GameMode.RIFT: 88>
ZONECONTROL = <GameMode.ZONECONTROL: 89>
IRONBANNERRIFT = <GameMode.IRONBANNERRIFT: 90>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class GatingScope(builtins.int, aiobungie.Enum):
58@typing.final
59class GatingScope(int, enums.Enum):
60    """An enum represents restrictive type of gating that is being performed by an entity.
61
62    This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity
63    applies to everyone equally, or to their specific Profile or Character states.
64    """
65
66    NONE = 0
67    GLOBAL = 1
68    CLAN = 2
69    PROFILE = 3
70    CHARACTER = 4
71    ITEM = 5
72    ASSUMED_WORST_CASE = 6

An enum represents restrictive type of gating that is being performed by an entity.

This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity applies to everyone equally, or to their specific Profile or Character states.

NONE = <GatingScope.NONE: 0>
GLOBAL = <GatingScope.GLOBAL: 1>
CLAN = <GatingScope.CLAN: 2>
PROFILE = <GatingScope.PROFILE: 3>
CHARACTER = <GatingScope.CHARACTER: 4>
ITEM = <GatingScope.ITEM: 5>
ASSUMED_WORST_CASE = <GatingScope.ASSUMED_WORST_CASE: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Gender(builtins.int, aiobungie.Enum):
484@typing.final
485class Gender(int, Enum):
486    """An Enum for Destiny Genders."""
487
488    MALE = 0
489    FEMALE = 1
490    UNKNOWN = 2

An Enum for Destiny Genders.

MALE = <Gender.MALE: 0>
FEMALE = <Gender.FEMALE: 1>
UNKNOWN = <Gender.UNKNOWN: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class GroupType(builtins.int, aiobungie.Enum):
653@typing.final
654class GroupType(int, Enum):
655    """An enums for the known bungie group types."""
656
657    GENERAL = 0
658    CLAN = 1

An enums for the known bungie group types.

GENERAL = <GroupType.GENERAL: 0>
CLAN = <GroupType.CLAN: 1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class HTTPError(aiobungie.AiobungieError):
79@attrs.define(auto_exc=True)
80class HTTPError(AiobungieError):
81    """Base HTTP request errors exception."""
82
83    message: str
84    """The error message."""
85
86    http_status: http.HTTPStatus
87    """The response status."""

Base HTTP request errors exception.

HTTPError(message: str, http_status: http.HTTPStatus)
2def __init__(self, message, http_status):
3    self.message = message
4    self.http_status = http_status
5    BaseException.__init__(self, self.message,self.http_status)

Method generated by attrs for class HTTPError.

message: str

The error message.

http_status: http.HTTPStatus

The response status.

Inherited Members
builtins.BaseException
with_traceback
@attrs.define(auto_exc=True, kw_only=True)
class HTTPException(aiobungie.HTTPError):
 90@attrs.define(auto_exc=True, kw_only=True)
 91class HTTPException(HTTPError):
 92    """An in-depth HTTP exception that's raised with more information."""
 93
 94    error_code: int
 95    """The returned Bungie error status code."""
 96
 97    http_status: http.HTTPStatus
 98    """The request response http status."""
 99
100    throttle_seconds: int
101    """The Bungie response throttle seconds."""
102
103    url: typing.Optional[typedefs.StrOrURL]
104    """The URL/endpoint caused this error."""
105
106    body: typing.Any
107    """The response body."""
108
109    headers: multidict.CIMultiDictProxy[str]
110    """The response headers."""
111
112    message: str
113    """A Bungie human readable message describes the cause of the error."""
114
115    error_status: str
116    """A Bungie short error status describes the cause of the error."""
117
118    message_data: dict[str, str]
119    """A dict of string key, value that includes each cause of the error
120    to a message describes information about that error.
121    """
122
123    def __str__(self) -> str:
124        if self.message:
125            message_body = self.message
126
127        if self.error_status:
128            error_status_body = self.error_status
129
130        return (
131            f"{self.http_status.name.replace('_', '').title()} {self.http_status.value}: "
132            f"Error status: {error_status_body}, Error message: {message_body} from {self.url} "
133            f"{str(self.body)}"
134        )

An in-depth HTTP exception that's raised with more information.

HTTPException( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class HTTPException.

error_code: int

The returned Bungie error status code.

http_status: http.HTTPStatus

The request response http status.

throttle_seconds: int

The Bungie response throttle seconds.

url: Union[str, yarl.URL, NoneType]

The URL/endpoint caused this error.

body: Any

The response body.

headers: multidict._multidict.CIMultiDictProxy[str]

The response headers.

message: str

A Bungie human readable message describes the cause of the error.

error_status: str

A Bungie short error status describes the cause of the error.

message_data: dict[str, str]

A dict of string key, value that includes each cause of the error to a message describes information about that error.

Inherited Members
builtins.BaseException
with_traceback
class Image:
 72class Image:
 73    """Representation of an image/avatar/picture at Bungie.
 74
 75    Example
 76    -------
 77    ```py
 78    from aiobungie import Image
 79    img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
 80    print(img)
 81    # https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg
 82
 83    # Stream the image.
 84    async for chunk in img:
 85        # Byte chunks of the image.
 86        print(chunk)
 87
 88    # Save the image to a file.
 89    await img.save("file_name", "/my/path/to/save/to", "jpeg")
 90    ```
 91
 92    Parameters
 93    ----------
 94    path : `str | None`
 95        The path to the image. If `None`, the default missing image path will be used.
 96    """
 97
 98    __slots__ = ("_path",)
 99
100    def __init__(self, path: typing.Optional[str] = None) -> None:
101        self._path = path
102
103    @property
104    def is_missing(self) -> bool:
105        return not self._path
106
107    @property
108    def url(self) -> str:
109        """The URL to the image."""
110        return self.create_url()
111
112    @staticmethod
113    def missing_path() -> str:
114        """Returns the path to the missing Bungie image."""
115        return "img/misc/missing_icon_d2.png"
116
117    def create_url(self) -> str:
118        """Creates a full URL to the image path.
119
120        Returns
121        -------
122        str
123            The URL to the image.
124        """
125        return f"{url.BASE}/{self._path if self._path else self.missing_path()}"
126
127    async def save(
128        self,
129        file_name: str,
130        path: typing.Union[pathlib.Path, str],
131        /,
132        mime_type: typing.Optional[typing.Union[MimeType, str]] = None,
133    ) -> None:
134        """Saves the image to a file.
135
136        Parameters
137        ----------
138        file_name : `str`
139            A name for the file to save the image to.
140        path : `pathlib.Path | str`
141            A path tp save the image to.
142
143        Other Parameters
144        ----------------
145        mime_type : `MimeType | str`
146            Optional MIME type of the image.
147
148        Raises
149        ------
150        `FileNotFoundError`
151            If the path provided does not exist.
152        `RuntimeError`
153            If the image could not be saved.
154        `PermissionError`
155            If the path provided is not writable or does not have write permissions.
156        """
157        if isinstance(path, pathlib.Path) and not path.exists():
158            raise FileNotFoundError(f"File does not exist: {path!r}")
159
160        if self.is_missing:
161            return
162
163        mimetype = mime_type or MimeType.PNG
164        path = pathlib.Path(path)
165
166        loop = helpers.get_or_make_loop()
167        pool = concurrent.futures.ThreadPoolExecutor()
168
169        try:
170            with pool:
171                await loop.run_in_executor(
172                    pool, _write, path, file_name, mimetype, await self.read()
173                )
174                _LOGGER.info("Saved image to %s", file_name)
175
176        except asyncio.CancelledError:
177            pass
178
179        except Exception as err:
180            raise RuntimeError("Encountered an error while saving image.") from err
181
182    async def read(self) -> bytes:
183        """Read this image bytes.
184
185        Returns
186        -------
187        `bytes`
188            The bytes of this image.
189        """
190        client_session = aiohttp.ClientSession()
191
192        try:
193            await client_session.__aenter__()
194            response = await client_session.get(self.create_url())
195
196            if 300 >= response.status >= 200:
197                reader = await response.read()
198
199        except Exception as exc:
200            raise RuntimeError(f"Failed to read image: {exc}") from None
201        finally:
202            await client_session.__aexit__(None, None, None)
203        return reader
204
205    async def iter(self) -> collections.AsyncGenerator[bytes, None]:
206        """Iterates over the image bytes lazily.
207
208        Example
209        -------
210        import aiobungie
211
212        resource = aiobungie.Image("img/misc/missing_icon_d2.png")
213        async for chunk in resource.iter():
214            print(chunk)
215
216        Returns
217        -------
218        `collections.AsyncGenerator[bytes, None]`
219            An async generator of the image bytes.
220        """
221
222        async for chunk in self:
223            yield chunk
224
225    def __repr__(self) -> str:
226        return f"Image(url={self.create_url()})"
227
228    def __str__(self) -> str:
229        return self.create_url()
230
231    def __aiter__(self) -> Image:
232        return self
233
234    async def __anext__(self) -> bytes:
235        return await self.read()
236
237    def __await__(self) -> collections.Generator[None, None, bytes]:
238        return self.__anext__().__await__()

Representation of an image/avatar/picture at Bungie.

Example
from aiobungie import Image
img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
print(img)
# https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg

# Stream the image.
async for chunk in img:
    # Byte chunks of the image.
    print(chunk)

# Save the image to a file.
await img.save("file_name", "/my/path/to/save/to", "jpeg")
Parameters
  • path (str | None): The path to the image. If None, the default missing image path will be used.
Image(path: Optional[str] = None)
100    def __init__(self, path: typing.Optional[str] = None) -> None:
101        self._path = path
url: str

The URL to the image.

@staticmethod
def missing_path() -> str:
112    @staticmethod
113    def missing_path() -> str:
114        """Returns the path to the missing Bungie image."""
115        return "img/misc/missing_icon_d2.png"

Returns the path to the missing Bungie image.

def create_url(self) -> str:
117    def create_url(self) -> str:
118        """Creates a full URL to the image path.
119
120        Returns
121        -------
122        str
123            The URL to the image.
124        """
125        return f"{url.BASE}/{self._path if self._path else self.missing_path()}"

Creates a full URL to the image path.

Returns
  • str: The URL to the image.
async def save( self, file_name: str, path: Union[pathlib.Path, str], /, mime_type: Union[aiobungie.internal.assets.MimeType, str, NoneType] = None) -> None:
127    async def save(
128        self,
129        file_name: str,
130        path: typing.Union[pathlib.Path, str],
131        /,
132        mime_type: typing.Optional[typing.Union[MimeType, str]] = None,
133    ) -> None:
134        """Saves the image to a file.
135
136        Parameters
137        ----------
138        file_name : `str`
139            A name for the file to save the image to.
140        path : `pathlib.Path | str`
141            A path tp save the image to.
142
143        Other Parameters
144        ----------------
145        mime_type : `MimeType | str`
146            Optional MIME type of the image.
147
148        Raises
149        ------
150        `FileNotFoundError`
151            If the path provided does not exist.
152        `RuntimeError`
153            If the image could not be saved.
154        `PermissionError`
155            If the path provided is not writable or does not have write permissions.
156        """
157        if isinstance(path, pathlib.Path) and not path.exists():
158            raise FileNotFoundError(f"File does not exist: {path!r}")
159
160        if self.is_missing:
161            return
162
163        mimetype = mime_type or MimeType.PNG
164        path = pathlib.Path(path)
165
166        loop = helpers.get_or_make_loop()
167        pool = concurrent.futures.ThreadPoolExecutor()
168
169        try:
170            with pool:
171                await loop.run_in_executor(
172                    pool, _write, path, file_name, mimetype, await self.read()
173                )
174                _LOGGER.info("Saved image to %s", file_name)
175
176        except asyncio.CancelledError:
177            pass
178
179        except Exception as err:
180            raise RuntimeError("Encountered an error while saving image.") from err

Saves the image to a file.

Parameters
  • file_name (str): A name for the file to save the image to.
  • path (pathlib.Path | str): A path tp save the image to.
Other Parameters
  • mime_type (MimeType | str): Optional MIME type of the image.
Raises
  • FileNotFoundError: If the path provided does not exist.
  • RuntimeError: If the image could not be saved.
  • PermissionError: If the path provided is not writable or does not have write permissions.
async def read(self) -> bytes:
182    async def read(self) -> bytes:
183        """Read this image bytes.
184
185        Returns
186        -------
187        `bytes`
188            The bytes of this image.
189        """
190        client_session = aiohttp.ClientSession()
191
192        try:
193            await client_session.__aenter__()
194            response = await client_session.get(self.create_url())
195
196            if 300 >= response.status >= 200:
197                reader = await response.read()
198
199        except Exception as exc:
200            raise RuntimeError(f"Failed to read image: {exc}") from None
201        finally:
202            await client_session.__aexit__(None, None, None)
203        return reader

Read this image bytes.

Returns
  • bytes: The bytes of this image.
async def iter(self) -> collections.abc.AsyncGenerator[bytes, None]:
205    async def iter(self) -> collections.AsyncGenerator[bytes, None]:
206        """Iterates over the image bytes lazily.
207
208        Example
209        -------
210        import aiobungie
211
212        resource = aiobungie.Image("img/misc/missing_icon_d2.png")
213        async for chunk in resource.iter():
214            print(chunk)
215
216        Returns
217        -------
218        `collections.AsyncGenerator[bytes, None]`
219            An async generator of the image bytes.
220        """
221
222        async for chunk in self:
223            yield chunk

Iterates over the image bytes lazily.

Example

import aiobungie

resource = aiobungie.Image("img/misc/missing_icon_d2.png") async for chunk in resource.iter(): print(chunk)

Returns
  • collections.AsyncGenerator[bytes, None]: An async generator of the image bytes.
@attrs.define(auto_exc=True)
class InternalServerError(aiobungie.HTTPException):
243@attrs.define(auto_exc=True)
244class InternalServerError(HTTPException):
245    """Raised for 5xx internal server errors."""

Raised for 5xx internal server errors.

InternalServerError( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class InternalServerError.

Inherited Members
HTTPException
error_code
http_status
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
@typing.final
class ItemBindStatus(builtins.int, aiobungie.Enum):
719@typing.final
720class ItemBindStatus(int, Enum):
721    """An enum for Destiny 2 items bind status."""
722
723    NOT_BOUND = 0
724    BOUND_TO_CHARACTER = 1
725    BOUND_TO_ACCOUNT = 2
726    BOUNT_TO_GUILD = 3

An enum for Destiny 2 items bind status.

NOT_BOUND = <ItemBindStatus.NOT_BOUND: 0>
BOUND_TO_CHARACTER = <ItemBindStatus.BOUND_TO_CHARACTER: 1>
BOUND_TO_ACCOUNT = <ItemBindStatus.BOUND_TO_ACCOUNT: 2>
BOUNT_TO_GUILD = <ItemBindStatus.BOUNT_TO_GUILD: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemLocation(builtins.int, aiobungie.Enum):
729@typing.final
730class ItemLocation(int, Enum):
731    """An enum for Destiny 2 items location."""
732
733    UNKNOWN = 0
734    INVENTORY = 1
735    VAULT = 2
736    VENDOR = 3
737    POSTMASTER = 4

An enum for Destiny 2 items location.

UNKNOWN = <ItemLocation.UNKNOWN: 0>
INVENTORY = <ItemLocation.INVENTORY: 1>
VAULT = <ItemLocation.VAULT: 2>
VENDOR = <ItemLocation.VENDOR: 3>
POSTMASTER = <ItemLocation.POSTMASTER: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemState(aiobungie.Flag):
754@typing.final
755class ItemState(Flag):
756    """An enum for Destiny 2 item states."""
757
758    NONE = 0
759    LOCKED = 1 << 0
760    TRACKED = 1 << 1
761    MASTERWORKED = 1 << 2
762    CRAFTED = 1 << 3
763    """If this bit is set, the item has been 'crafted' by the player."""
764    HIGHLITED_OBJECTIVE = 1 << 4
765    """If this bit is set, the item is a 'highlighted' objective."""

An enum for Destiny 2 item states.

NONE = <ItemState.NONE: 0>
LOCKED = <ItemState.LOCKED: 1>
TRACKED = <ItemState.TRACKED: 2>
MASTERWORKED = <ItemState.MASTERWORKED: 4>
CRAFTED = <ItemState.CRAFTED: 8>

If this bit is set, the item has been 'crafted' by the player.

HIGHLITED_OBJECTIVE = <ItemState.HIGHLITED_OBJECTIVE: 16>

If this bit is set, the item is a 'highlighted' objective.

Inherited Members
Flag
name
value
@typing.final
class ItemSubType(builtins.int, aiobungie.Enum):
586@typing.final
587class ItemSubType(int, Enum):
588    """An enum for Destiny 2 inventory items subtype."""
589
590    NONE = 0
591    AUTORIFLE = 6
592    SHOTGUN = 7
593    MACHINEGUN = 8
594    HANDCANNON = 9
595    ROCKETLAUNCHER = 10
596    FUSIONRIFLE = 11
597    SNIPERRIFLE = 12
598    PULSERIFLE = 13
599    SCOUTRIFLE = 14
600    SIDEARM = 17
601    SWORD = 18
602    MASK = 19
603    SHADER = 20
604    ORNAMENT = 21
605    FUSIONRIFLELINE = 22
606    GRENADELAUNCHER = 23
607    SUBMACHINEGUN = 24
608    TRACERIFLE = 25
609    HELMETARMOR = 26
610    GAUNTLETSARMOR = 27
611    CHESTARMOR = 28
612    LEGARMOR = 29
613    CLASSARMOR = 30
614    BOW = 31
615    DUMMYREPEATABLEBOUNTY = 32

An enum for Destiny 2 inventory items subtype.

NONE = <ItemSubType.NONE: 0>
AUTORIFLE = <ItemSubType.AUTORIFLE: 6>
SHOTGUN = <ItemSubType.SHOTGUN: 7>
MACHINEGUN = <ItemSubType.MACHINEGUN: 8>
HANDCANNON = <ItemSubType.HANDCANNON: 9>
ROCKETLAUNCHER = <ItemSubType.ROCKETLAUNCHER: 10>
FUSIONRIFLE = <ItemSubType.FUSIONRIFLE: 11>
SNIPERRIFLE = <ItemSubType.SNIPERRIFLE: 12>
PULSERIFLE = <ItemSubType.PULSERIFLE: 13>
SCOUTRIFLE = <ItemSubType.SCOUTRIFLE: 14>
SIDEARM = <ItemSubType.SIDEARM: 17>
SWORD = <ItemSubType.SWORD: 18>
MASK = <ItemSubType.MASK: 19>
SHADER = <ItemSubType.SHADER: 20>
ORNAMENT = <ItemSubType.ORNAMENT: 21>
FUSIONRIFLELINE = <ItemSubType.FUSIONRIFLELINE: 22>
GRENADELAUNCHER = <ItemSubType.GRENADELAUNCHER: 23>
SUBMACHINEGUN = <ItemSubType.SUBMACHINEGUN: 24>
TRACERIFLE = <ItemSubType.TRACERIFLE: 25>
HELMETARMOR = <ItemSubType.HELMETARMOR: 26>
GAUNTLETSARMOR = <ItemSubType.GAUNTLETSARMOR: 27>
CHESTARMOR = <ItemSubType.CHESTARMOR: 28>
LEGARMOR = <ItemSubType.LEGARMOR: 29>
CLASSARMOR = <ItemSubType.CLASSARMOR: 30>
BOW = <ItemSubType.BOW: 31>
DUMMYREPEATABLEBOUNTY = <ItemSubType.DUMMYREPEATABLEBOUNTY: 32>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemTier(builtins.int, aiobungie.Enum):
618@typing.final
619class ItemTier(int, Enum):
620    """An enum for a Destiny 2 item tier."""
621
622    NONE = 0
623    BASIC = 3340296461
624    COMMON = 2395677314
625    RARE = 2127292149
626    LEGENDERY = 4008398120
627    EXOTIC = 2759499571

An enum for a Destiny 2 item tier.

NONE = <ItemTier.NONE: 0>
BASIC = <ItemTier.BASIC: 3340296461>
COMMON = <ItemTier.COMMON: 2395677314>
RARE = <ItemTier.RARE: 2127292149>
LEGENDERY = <ItemTier.LEGENDERY: 4008398120>
EXOTIC = <ItemTier.EXOTIC: 2759499571>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemType(builtins.int, aiobungie.Enum):
553@typing.final
554class ItemType(int, Enum):
555    """Enums for Destiny2's item types."""
556
557    NONE = 0
558    CURRENCY = 1
559    ARMOR = 2
560    WEAPON = 3
561    MESSAGE = 7
562    ENGRAM = 8
563    CONSUMABLE = 9
564    EXCHANGEMATERIAL = 10
565    MISSIONREWARD = 11
566    QUESTSTEP = 12
567    QUESTSTEPCOMPLETE = 13
568    EMBLEM = 14
569    QUEST = 15
570    SUBCLASS = 16
571    CLANBANNER = 17
572    AURA = 18
573    MOD = 19
574    DUMMY = 20
575    SHIP = 21
576    VEHICLE = 22
577    EMOTE = 23
578    GHOST = 24
579    PACKAGE = 25
580    BOUNTY = 26
581    WRAPPER = 27
582    SEASONALARTIFACT = 28
583    FINISHER = 29

Enums for Destiny2's item types.

NONE = <ItemType.NONE: 0>
CURRENCY = <ItemType.CURRENCY: 1>
ARMOR = <ItemType.ARMOR: 2>
WEAPON = <ItemType.WEAPON: 3>
MESSAGE = <ItemType.MESSAGE: 7>
ENGRAM = <ItemType.ENGRAM: 8>
CONSUMABLE = <ItemType.CONSUMABLE: 9>
EXCHANGEMATERIAL = <ItemType.EXCHANGEMATERIAL: 10>
MISSIONREWARD = <ItemType.MISSIONREWARD: 11>
QUESTSTEP = <ItemType.QUESTSTEP: 12>
QUESTSTEPCOMPLETE = <ItemType.QUESTSTEPCOMPLETE: 13>
EMBLEM = <ItemType.EMBLEM: 14>
QUEST = <ItemType.QUEST: 15>
SUBCLASS = <ItemType.SUBCLASS: 16>
CLANBANNER = <ItemType.CLANBANNER: 17>
AURA = <ItemType.AURA: 18>
MOD = <ItemType.MOD: 19>
DUMMY = <ItemType.DUMMY: 20>
SHIP = <ItemType.SHIP: 21>
VEHICLE = <ItemType.VEHICLE: 22>
EMOTE = <ItemType.EMOTE: 23>
GHOST = <ItemType.GHOST: 24>
PACKAGE = <ItemType.PACKAGE: 25>
BOUNTY = <ItemType.BOUNTY: 26>
WRAPPER = <ItemType.WRAPPER: 27>
SEASONALARTIFACT = <ItemType.SEASONALARTIFACT: 28>
FINISHER = <ItemType.FINISHER: 29>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class Iterator(typing.Generic[~Item]):
 45class Iterator(typing.Generic[Item]):
 46    """A Flat, In-Memory iterator for sequenced based data.
 47
 48    Example
 49    -------
 50    ```py
 51    iterator = Iterator([1, 2, 3])
 52
 53    # Map the results.
 54    for item in iterator.map(lambda item: item * 2):
 55        print(item)
 56    # 2
 57    # 4
 58
 59    # Indexing is also supported.
 60    print(iterator[0])
 61    # 1
 62
 63    # Normal iteration.
 64    for item in iterator:
 65        print(item)
 66    # 1
 67    # 2
 68    # 3
 69
 70    # Union two iterators.
 71    iterator2 = Iterator([4, 5, 6])
 72    final = iterator | iterator2
 73    # <Iterator([1, 2, 3, 4, 5, 6])>
 74    ```
 75
 76    Parameters
 77    ----------
 78    items: `collections.Iterable[Item]`
 79        The items to iterate over.
 80    """
 81
 82    __slots__ = ("_items",)
 83
 84    def __init__(self, items: collections.Iterable[Item]) -> None:
 85        self._items = iter(items)
 86
 87    @typing.overload
 88    def collect(self) -> list[Item]:
 89        ...
 90
 91    @typing.overload
 92    def collect(self, casting: _B) -> list[_B]:
 93        ...
 94
 95    def collect(
 96        self, casting: typing.Optional[_B] = None
 97    ) -> typing.Union[list[Item], list[_B]]:
 98        """Collects all items in the iterator into a list and cast them into an object if provided.
 99
100        Example
101        -------
102        >>> iterator = Iterator([1, 2, 3])
103        >>> iterator.collect(casting=str)
104        ["1", "2", "3"]
105
106        Parameters
107        ----------
108        casting: `T | None`
109            The type to cast the items to. If `None` is provided, the items will be returned as is.
110
111        Raises
112        ------
113        `StopIteration`
114            If no elements are left in the iterator.
115        """
116        if casting is not None:
117            return typing.cast(list[_B], list(map(casting, self._items)))
118
119        return list(self._items)
120
121    def next(self) -> Item:
122        """Returns the next item in the iterator.
123
124        Example
125        -------
126        ```py
127        iterator = Iterator(["1", "2", "3"])
128        item = iterator.next()
129        assert item == "1"
130        item = iterator.next()
131        assert item == "2"
132        ```
133
134        Raises
135        ------
136        `StopIteration`
137            If no elements are left in the iterator.
138        """
139        try:
140            return self.__next__()
141        except StopIteration:
142            self._ok()
143
144    def map(
145        self, predicate: collections.Callable[[Item], OtherItem]
146    ) -> Iterator[OtherItem]:
147        """Maps each item in the iterator to its predicated value.
148
149        Example
150        -------
151        ```py
152        iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value))
153        print(iterator)
154        # <Iterator([1, 2, 3])>
155        ```
156
157        Parameters
158        ----------
159        predicate: `collections.Callable[[Item], OtherItem]`
160            The function to map each item in the iterator to its predicated value.
161
162        Returns
163        -------
164        `Iterator[OtherItem]`
165            The mapped iterator.
166
167        Raises
168        ------
169        `StopIteration`
170            If no elements are left in the iterator.
171        """
172        return Iterator(map(predicate, self._items))
173
174    def take(self, n: int) -> Iterator[Item]:
175        """Take the first number of items until the number of items are yielded or
176        the end of the iterator is reached.
177
178        Example
179        -------
180        ```py
181        iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
182        print(iterator.take(2))
183        # <Iterator([GameMode.RAID, GameMode.STRIKE])>
184        ```
185
186        Parameters
187        ----------
188        n: `int`
189            The number of items to take.
190
191        Raises
192        ------
193        `StopIteration`
194            If no elements are left in the iterator.
195        """
196        return Iterator(itertools.islice(self._items, n))
197
198    def take_while(
199        self, predicate: collections.Callable[[Item], bool]
200    ) -> Iterator[Item]:
201        """Yields items from the iterator while predicate returns `True`.
202
203        Example
204        -------
205        ```py
206        iterator = Iterator([STEAM, XBOX, STADIA])
207        print(iterator.take_while(lambda platform: platform is not XBOX))
208        # <Iterator([STEAM])>
209        ```
210
211        Parameters
212        ----------
213        predicate: `collections.Callable[[Item], bool]`
214            The function to predicate each item in the iterator.
215
216        Raises
217        ------
218        `StopIteration`
219            If no elements are left in the iterator.
220        """
221        return Iterator(itertools.takewhile(predicate, self._items))
222
223    def drop_while(
224        self, predicate: collections.Callable[[Item], bool]
225    ) -> Iterator[Item]:
226        """Yields items from the iterator while predicate returns `False`.
227
228        Example
229        -------
230        ```py
231        iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
232        print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
233        # <Iterator([DestinyMembership(name="Bob")])>
234        ```
235
236        Parameters
237        ----------
238        predicate: `collections.Callable[[Item], bool]`
239            The function to predicate each item in the iterator.
240
241        Raises
242        ------
243        `StopIteration`
244            If no elements are left in the iterator.
245        """
246        return Iterator(itertools.dropwhile(predicate, self._items))
247
248    def filter(self, predicate: collections.Callable[[Item], bool]) -> Iterator[Item]:
249        """Filters the iterator to only yield items that match the predicate.
250
251        Example
252        -------
253        ```py
254        names = Iterator(["Jim", "Bob", "Mike", "Jess"])
255        print(names.filter(lambda n: n != "Jim"))
256        # <Iterator(["Bob", "Mike", "Jess"])>
257        ```
258        """
259        return Iterator(filter(predicate, self._items))
260
261    def skip(self, n: int) -> Iterator[Item]:
262        """Skips the first number of items in the iterator.
263
264        Example
265        -------
266        ```py
267        iterator = Iterator([STEAM, XBOX, STADIA])
268        print(iterator.skip(1))
269        # <Iterator([XBOX, STADIA])>
270        ```
271        """
272        return Iterator(itertools.islice(self._items, n, None))
273
274    def zip(self, other: Iterator[OtherItem]) -> Iterator[tuple[Item, OtherItem]]:
275        """Zips the iterator with another iterable.
276
277        Example
278        -------
279        ```py
280        iterator = Iterator([1, 3, 5])
281        other = Iterator([2, 4, 6])
282        for item, other_item in iterator.zip(other):
283            print(item, other_item)
284        # <Iterator([(1, 2), (3, 4), (5, 6)])>
285        ```
286
287        Parameters
288        ----------
289        other: `Iterator[OtherItem]`
290            The iterable to zip with.
291
292        Raises
293        ------
294        `StopIteration`
295            If no elements are left in the iterator.
296        """
297        return Iterator(zip(self._items, other))
298
299    def all(self, predicate: collections.Callable[[Item], bool]) -> bool:
300        """`True` if all items in the iterator match the predicate.
301
302        Example
303        -------
304        ```py
305        iterator = Iterator([1, 2, 3])
306        while iterator.all(lambda item: isinstance(item, int)):
307            print("Still all integers")
308            continue
309        # Still all integers
310        ```
311
312        Parameters
313        ----------
314        predicate: `collections.Callable[[Item], bool]`
315            The function to test each item in the iterator.
316
317        Raises
318        ------
319        `StopIteration`
320            If no elements are left in the iterator.
321        """
322        return all(predicate(item) for item in self)
323
324    def any(self, predicate: collections.Callable[[Item], bool]) -> bool:
325        """`True` if any items in the iterator match the predicate.
326
327        Example
328        -------
329        ```py
330        iterator = Iterator([1, 2, 3])
331        if iterator.any(lambda item: isinstance(item, int)):
332            print("At least one item is an int.")
333        # At least one item is an int.
334        ```
335
336        Parameters
337        ----------
338        predicate: `collections.Callable[[Item], bool]`
339            The function to test each item in the iterator.
340
341        Raises
342        ------
343        `StopIteration`
344            If no elements are left in the iterator.
345        """
346        return any(predicate(item) for item in self)
347
348    def sort(
349        self,
350        *,
351        key: collections.Callable[[Item], typeshed.SupportsRichComparison],
352        reverse: bool = False,
353    ) -> Iterator[Item]:
354        """Sorts the iterator.
355
356        Example
357        -------
358        ```py
359        iterator = Iterator([3, 1, 6, 7])
360        print(iterator.sort(key=lambda item: item))
361        # <Iterator([1, 3, 6, 7])>
362        ```
363
364        Parameters
365        ----------
366        key: `collections.Callable[[Item], Any]`
367            The function to sort by.
368        reverse: `bool`
369            Whether to reverse the sort.
370
371        Raises
372        ------
373        `StopIteration`
374            If no elements are left in the iterator.
375        """
376        return Iterator(sorted(self._items, key=key, reverse=reverse))
377
378    def first(self) -> Item:
379        """Returns the first item in the iterator.
380
381        Example
382        -------
383        ```py
384        iterator = Iterator([3, 1, 6, 7])
385        print(iterator.first())
386        3
387        ```
388
389        Raises
390        ------
391        `StopIteration`
392            If no elements are left in the iterator.
393        """
394        return self.take(1).next()
395
396    def reversed(self) -> Iterator[Item]:
397        """Returns a new iterator that yields the items in the iterator in reverse order.
398
399        Example
400        -------
401        ```py
402        iterator = Iterator([3, 1, 6, 7])
403        print(iterator.reversed())
404        # <Iterator([7, 6, 1, 3])>
405        ```
406
407        Raises
408        ------
409        `StopIteration`
410            If no elements are left in the iterator.
411        """
412        return Iterator(reversed(self.collect()))
413
414    def count(self) -> int:
415        """Returns the number of items in the iterator.
416
417        Example
418        -------
419        ```py
420        iterator = Iterator([3, 1, 6, 7])
421        print(iterator.count())
422        4
423        ```
424        """
425        count = 0
426        for _ in self:
427            count += 1
428
429        return count
430
431    def union(self, other: Iterator[Item]) -> Iterator[Item]:
432        """Returns a new iterator that yields all items from both iterators.
433
434        Example
435        -------
436        ```py
437        iterator = Iterator([1, 2, 3])
438        other = Iterator([4, 5, 6])
439        print(iterator.union(other))
440        # <Iterator([1, 2, 3, 4, 5, 6])>
441        ```
442
443        Parameters
444        ----------
445        other: `Iterator[Item]`
446            The iterable to union with.
447
448        Raises
449        ------
450        `StopIteration`
451            If no elements are left in the iterator.
452        """
453        return Iterator(itertools.chain(self._items, other))
454
455    def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None:
456        """Calls the function on each item in the iterator.
457
458        Example
459        -------
460        ```py
461        iterator = Iterator([1, 2, 3])
462        iterator.for_each(lambda item: print(item))
463        # 1
464        # 2
465        # 3
466        ```
467
468        Parameters
469        ----------
470        func: `typeshed.Callable[[Item], None]`
471            The function to call on each item in the iterator.
472        """
473        for item in self:
474            func(item)
475
476    async def async_for_each(
477        self,
478        func: collections.Callable[[Item], collections.Coroutine[None, None, None]],
479    ) -> None:
480        """Calls the async function on each item in the iterator concurrently.
481
482        Example
483        -------
484        ```py
485        async def signup(username: str) -> None:
486            async with aiohttp.request('POST', '...') as r:
487                # Actual logic.
488                ...
489
490        async def main():
491            users = aiobungie.into_iter(["user_danny", "user_jojo"])
492            await users.async_for_each(lambda username: signup(username))
493        ```
494
495        Parameters
496        ----------
497        func: `collections.Callable[[Item], collections.Coroutine[None, None, None]]`
498            The async function to call on each item in the iterator.
499        """
500        await _helpers.awaits(*(func(item) for item in self))
501
502    def enumerate(self, *, start: int = 0) -> Iterator[tuple[int, Item]]:
503        """Returns a new iterator that yields tuples of the index and item.
504
505        Example
506        -------
507        ```py
508        iterator = Iterator([1, 2, 3])
509        for index, item in iterator.enumerate():
510            print(index, item)
511        # 0 1
512        # 1 2
513        # 2 3
514        ```
515
516        Raises
517        ------
518        `StopIteration`
519            If no elements are left in the iterator.
520        """
521        return Iterator(enumerate(self._items, start=start))
522
523    def _ok(self) -> typing.NoReturn:
524        raise StopIteration("No more items in the iterator.") from None
525
526    def __getitem__(self, index: int) -> Item:
527        try:
528            return self.skip(index).first()
529        except IndexError:
530            self._ok()
531
532    def __or__(self, other: Iterator[Item]) -> Iterator[Item]:
533        return self.union(other)
534
535    # This is a never.
536    def __setitem__(self) -> typing.NoReturn:
537        raise TypeError(
538            f"{type(self).__name__} doesn't support item assignment."
539        ) from None
540
541    def __repr__(self) -> str:
542        return f'<{self.__class__.__name__}({", ".join([str(item) for item in self])})>'
543
544    def __len__(self) -> int:
545        return self.count()
546
547    def __iter__(self) -> Iterator[Item]:
548        return self
549
550    def __next__(self) -> Item:
551        try:
552            item = next(self._items)
553        except StopIteration:
554            self._ok()
555
556        return item

A Flat, In-Memory iterator for sequenced based data.

Example
iterator = Iterator([1, 2, 3])

# Map the results.
for item in iterator.map(lambda item: item * 2):
    print(item)
# 2
# 4

# Indexing is also supported.
print(iterator[0])
# 1

# Normal iteration.
for item in iterator:
    print(item)
# 1
# 2
# 3

# Union two iterators.
iterator2 = Iterator([4, 5, 6])
final = iterator | iterator2
# <Iterator([1, 2, 3, 4, 5, 6])>
Parameters
  • items (collections.Iterable[Item]): The items to iterate over.
Iterator(items: collections.abc.Iterable[~Item])
84    def __init__(self, items: collections.Iterable[Item]) -> None:
85        self._items = iter(items)
def collect( self, casting: 'typing.Optional[_B]' = None) -> 'typing.Union[list[Item], list[_B]]':
 95    def collect(
 96        self, casting: typing.Optional[_B] = None
 97    ) -> typing.Union[list[Item], list[_B]]:
 98        """Collects all items in the iterator into a list and cast them into an object if provided.
 99
100        Example
101        -------
102        >>> iterator = Iterator([1, 2, 3])
103        >>> iterator.collect(casting=str)
104        ["1", "2", "3"]
105
106        Parameters
107        ----------
108        casting: `T | None`
109            The type to cast the items to. If `None` is provided, the items will be returned as is.
110
111        Raises
112        ------
113        `StopIteration`
114            If no elements are left in the iterator.
115        """
116        if casting is not None:
117            return typing.cast(list[_B], list(map(casting, self._items)))
118
119        return list(self._items)

Collects all items in the iterator into a list and cast them into an object if provided.

Example
>>> iterator = Iterator([1, 2, 3])
>>> iterator.collect(casting=str)
["1", "2", "3"]
Parameters
  • casting (T | None): The type to cast the items to. If None is provided, the items will be returned as is.
Raises
  • StopIteration: If no elements are left in the iterator.
def next(self) -> ~Item:
121    def next(self) -> Item:
122        """Returns the next item in the iterator.
123
124        Example
125        -------
126        ```py
127        iterator = Iterator(["1", "2", "3"])
128        item = iterator.next()
129        assert item == "1"
130        item = iterator.next()
131        assert item == "2"
132        ```
133
134        Raises
135        ------
136        `StopIteration`
137            If no elements are left in the iterator.
138        """
139        try:
140            return self.__next__()
141        except StopIteration:
142            self._ok()

Returns the next item in the iterator.

Example
iterator = Iterator(["1", "2", "3"])
item = iterator.next()
assert item == "1"
item = iterator.next()
assert item == "2"
Raises
  • StopIteration: If no elements are left in the iterator.
def map( self, predicate: 'collections.Callable[[Item], OtherItem]') -> 'Iterator[OtherItem]':
144    def map(
145        self, predicate: collections.Callable[[Item], OtherItem]
146    ) -> Iterator[OtherItem]:
147        """Maps each item in the iterator to its predicated value.
148
149        Example
150        -------
151        ```py
152        iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value))
153        print(iterator)
154        # <Iterator([1, 2, 3])>
155        ```
156
157        Parameters
158        ----------
159        predicate: `collections.Callable[[Item], OtherItem]`
160            The function to map each item in the iterator to its predicated value.
161
162        Returns
163        -------
164        `Iterator[OtherItem]`
165            The mapped iterator.
166
167        Raises
168        ------
169        `StopIteration`
170            If no elements are left in the iterator.
171        """
172        return Iterator(map(predicate, self._items))

Maps each item in the iterator to its predicated value.

Example
iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value))
print(iterator)
# <Iterator([1, 2, 3])>
Parameters
  • predicate (collections.Callable[[Item], OtherItem]): The function to map each item in the iterator to its predicated value.
Returns
  • Iterator[OtherItem]: The mapped iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def take(self, n: int) -> aiobungie.Iterator[~Item]:
174    def take(self, n: int) -> Iterator[Item]:
175        """Take the first number of items until the number of items are yielded or
176        the end of the iterator is reached.
177
178        Example
179        -------
180        ```py
181        iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
182        print(iterator.take(2))
183        # <Iterator([GameMode.RAID, GameMode.STRIKE])>
184        ```
185
186        Parameters
187        ----------
188        n: `int`
189            The number of items to take.
190
191        Raises
192        ------
193        `StopIteration`
194            If no elements are left in the iterator.
195        """
196        return Iterator(itertools.islice(self._items, n))

Take the first number of items until the number of items are yielded or the end of the iterator is reached.

Example
iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
print(iterator.take(2))
# <Iterator([GameMode.RAID, GameMode.STRIKE])>
Parameters
  • n (int): The number of items to take.
Raises
  • StopIteration: If no elements are left in the iterator.
def take_while( self, predicate: collections.abc.Callable[[~Item], bool]) -> aiobungie.Iterator[~Item]:
198    def take_while(
199        self, predicate: collections.Callable[[Item], bool]
200    ) -> Iterator[Item]:
201        """Yields items from the iterator while predicate returns `True`.
202
203        Example
204        -------
205        ```py
206        iterator = Iterator([STEAM, XBOX, STADIA])
207        print(iterator.take_while(lambda platform: platform is not XBOX))
208        # <Iterator([STEAM])>
209        ```
210
211        Parameters
212        ----------
213        predicate: `collections.Callable[[Item], bool]`
214            The function to predicate each item in the iterator.
215
216        Raises
217        ------
218        `StopIteration`
219            If no elements are left in the iterator.
220        """
221        return Iterator(itertools.takewhile(predicate, self._items))

Yields items from the iterator while predicate returns True.

Example
iterator = Iterator([STEAM, XBOX, STADIA])
print(iterator.take_while(lambda platform: platform is not XBOX))
# <Iterator([STEAM])>
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def drop_while( self, predicate: collections.abc.Callable[[~Item], bool]) -> aiobungie.Iterator[~Item]:
223    def drop_while(
224        self, predicate: collections.Callable[[Item], bool]
225    ) -> Iterator[Item]:
226        """Yields items from the iterator while predicate returns `False`.
227
228        Example
229        -------
230        ```py
231        iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
232        print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
233        # <Iterator([DestinyMembership(name="Bob")])>
234        ```
235
236        Parameters
237        ----------
238        predicate: `collections.Callable[[Item], bool]`
239            The function to predicate each item in the iterator.
240
241        Raises
242        ------
243        `StopIteration`
244            If no elements are left in the iterator.
245        """
246        return Iterator(itertools.dropwhile(predicate, self._items))

Yields items from the iterator while predicate returns False.

Example
iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
# <Iterator([DestinyMembership(name="Bob")])>
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def filter( self, predicate: collections.abc.Callable[[~Item], bool]) -> aiobungie.Iterator[~Item]:
248    def filter(self, predicate: collections.Callable[[Item], bool]) -> Iterator[Item]:
249        """Filters the iterator to only yield items that match the predicate.
250
251        Example
252        -------
253        ```py
254        names = Iterator(["Jim", "Bob", "Mike", "Jess"])
255        print(names.filter(lambda n: n != "Jim"))
256        # <Iterator(["Bob", "Mike", "Jess"])>
257        ```
258        """
259        return Iterator(filter(predicate, self._items))

Filters the iterator to only yield items that match the predicate.

Example
names = Iterator(["Jim", "Bob", "Mike", "Jess"])
print(names.filter(lambda n: n != "Jim"))
# <Iterator(["Bob", "Mike", "Jess"])>
def skip(self, n: int) -> aiobungie.Iterator[~Item]:
261    def skip(self, n: int) -> Iterator[Item]:
262        """Skips the first number of items in the iterator.
263
264        Example
265        -------
266        ```py
267        iterator = Iterator([STEAM, XBOX, STADIA])
268        print(iterator.skip(1))
269        # <Iterator([XBOX, STADIA])>
270        ```
271        """
272        return Iterator(itertools.islice(self._items, n, None))

Skips the first number of items in the iterator.

Example
iterator = Iterator([STEAM, XBOX, STADIA])
print(iterator.skip(1))
# <Iterator([XBOX, STADIA])>
def zip(self, other: 'Iterator[OtherItem]') -> 'Iterator[tuple[Item, OtherItem]]':
274    def zip(self, other: Iterator[OtherItem]) -> Iterator[tuple[Item, OtherItem]]:
275        """Zips the iterator with another iterable.
276
277        Example
278        -------
279        ```py
280        iterator = Iterator([1, 3, 5])
281        other = Iterator([2, 4, 6])
282        for item, other_item in iterator.zip(other):
283            print(item, other_item)
284        # <Iterator([(1, 2), (3, 4), (5, 6)])>
285        ```
286
287        Parameters
288        ----------
289        other: `Iterator[OtherItem]`
290            The iterable to zip with.
291
292        Raises
293        ------
294        `StopIteration`
295            If no elements are left in the iterator.
296        """
297        return Iterator(zip(self._items, other))

Zips the iterator with another iterable.

Example
iterator = Iterator([1, 3, 5])
other = Iterator([2, 4, 6])
for item, other_item in iterator.zip(other):
    print(item, other_item)
# <Iterator([(1, 2), (3, 4), (5, 6)])>
Parameters
  • other (Iterator[OtherItem]): The iterable to zip with.
Raises
  • StopIteration: If no elements are left in the iterator.
def all(self, predicate: collections.abc.Callable[[~Item], bool]) -> bool:
299    def all(self, predicate: collections.Callable[[Item], bool]) -> bool:
300        """`True` if all items in the iterator match the predicate.
301
302        Example
303        -------
304        ```py
305        iterator = Iterator([1, 2, 3])
306        while iterator.all(lambda item: isinstance(item, int)):
307            print("Still all integers")
308            continue
309        # Still all integers
310        ```
311
312        Parameters
313        ----------
314        predicate: `collections.Callable[[Item], bool]`
315            The function to test each item in the iterator.
316
317        Raises
318        ------
319        `StopIteration`
320            If no elements are left in the iterator.
321        """
322        return all(predicate(item) for item in self)

True if all items in the iterator match the predicate.

Example
iterator = Iterator([1, 2, 3])
while iterator.all(lambda item: isinstance(item, int)):
    print("Still all integers")
    continue
# Still all integers
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def any(self, predicate: collections.abc.Callable[[~Item], bool]) -> bool:
324    def any(self, predicate: collections.Callable[[Item], bool]) -> bool:
325        """`True` if any items in the iterator match the predicate.
326
327        Example
328        -------
329        ```py
330        iterator = Iterator([1, 2, 3])
331        if iterator.any(lambda item: isinstance(item, int)):
332            print("At least one item is an int.")
333        # At least one item is an int.
334        ```
335
336        Parameters
337        ----------
338        predicate: `collections.Callable[[Item], bool]`
339            The function to test each item in the iterator.
340
341        Raises
342        ------
343        `StopIteration`
344            If no elements are left in the iterator.
345        """
346        return any(predicate(item) for item in self)

True if any items in the iterator match the predicate.

Example
iterator = Iterator([1, 2, 3])
if iterator.any(lambda item: isinstance(item, int)):
    print("At least one item is an int.")
# At least one item is an int.
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def sort( self, *, key: 'collections.Callable[[Item], typeshed.SupportsRichComparison]', reverse: bool = False) -> aiobungie.Iterator[~Item]:
348    def sort(
349        self,
350        *,
351        key: collections.Callable[[Item], typeshed.SupportsRichComparison],
352        reverse: bool = False,
353    ) -> Iterator[Item]:
354        """Sorts the iterator.
355
356        Example
357        -------
358        ```py
359        iterator = Iterator([3, 1, 6, 7])
360        print(iterator.sort(key=lambda item: item))
361        # <Iterator([1, 3, 6, 7])>
362        ```
363
364        Parameters
365        ----------
366        key: `collections.Callable[[Item], Any]`
367            The function to sort by.
368        reverse: `bool`
369            Whether to reverse the sort.
370
371        Raises
372        ------
373        `StopIteration`
374            If no elements are left in the iterator.
375        """
376        return Iterator(sorted(self._items, key=key, reverse=reverse))

Sorts the iterator.

Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.sort(key=lambda item: item))
# <Iterator([1, 3, 6, 7])>
Parameters
  • key (collections.Callable[[Item], Any]): The function to sort by.
  • reverse (bool): Whether to reverse the sort.
Raises
  • StopIteration: If no elements are left in the iterator.
def first(self) -> ~Item:
378    def first(self) -> Item:
379        """Returns the first item in the iterator.
380
381        Example
382        -------
383        ```py
384        iterator = Iterator([3, 1, 6, 7])
385        print(iterator.first())
386        3
387        ```
388
389        Raises
390        ------
391        `StopIteration`
392            If no elements are left in the iterator.
393        """
394        return self.take(1).next()

Returns the first item in the iterator.

Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.first())
3
Raises
  • StopIteration: If no elements are left in the iterator.
def reversed(self) -> aiobungie.Iterator[~Item]:
396    def reversed(self) -> Iterator[Item]:
397        """Returns a new iterator that yields the items in the iterator in reverse order.
398
399        Example
400        -------
401        ```py
402        iterator = Iterator([3, 1, 6, 7])
403        print(iterator.reversed())
404        # <Iterator([7, 6, 1, 3])>
405        ```
406
407        Raises
408        ------
409        `StopIteration`
410            If no elements are left in the iterator.
411        """
412        return Iterator(reversed(self.collect()))

Returns a new iterator that yields the items in the iterator in reverse order.

Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.reversed())
# <Iterator([7, 6, 1, 3])>
Raises
  • StopIteration: If no elements are left in the iterator.
def count(self) -> int:
414    def count(self) -> int:
415        """Returns the number of items in the iterator.
416
417        Example
418        -------
419        ```py
420        iterator = Iterator([3, 1, 6, 7])
421        print(iterator.count())
422        4
423        ```
424        """
425        count = 0
426        for _ in self:
427            count += 1
428
429        return count

Returns the number of items in the iterator.

Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.count())
4
def union( self, other: aiobungie.Iterator[~Item]) -> aiobungie.Iterator[~Item]:
431    def union(self, other: Iterator[Item]) -> Iterator[Item]:
432        """Returns a new iterator that yields all items from both iterators.
433
434        Example
435        -------
436        ```py
437        iterator = Iterator([1, 2, 3])
438        other = Iterator([4, 5, 6])
439        print(iterator.union(other))
440        # <Iterator([1, 2, 3, 4, 5, 6])>
441        ```
442
443        Parameters
444        ----------
445        other: `Iterator[Item]`
446            The iterable to union with.
447
448        Raises
449        ------
450        `StopIteration`
451            If no elements are left in the iterator.
452        """
453        return Iterator(itertools.chain(self._items, other))

Returns a new iterator that yields all items from both iterators.

Example
iterator = Iterator([1, 2, 3])
other = Iterator([4, 5, 6])
print(iterator.union(other))
# <Iterator([1, 2, 3, 4, 5, 6])>
Parameters
  • other (Iterator[Item]): The iterable to union with.
Raises
  • StopIteration: If no elements are left in the iterator.
def for_each(self, func: collections.abc.Callable[[~Item], typing.Any]) -> None:
455    def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None:
456        """Calls the function on each item in the iterator.
457
458        Example
459        -------
460        ```py
461        iterator = Iterator([1, 2, 3])
462        iterator.for_each(lambda item: print(item))
463        # 1
464        # 2
465        # 3
466        ```
467
468        Parameters
469        ----------
470        func: `typeshed.Callable[[Item], None]`
471            The function to call on each item in the iterator.
472        """
473        for item in self:
474            func(item)

Calls the function on each item in the iterator.

Example
iterator = Iterator([1, 2, 3])
iterator.for_each(lambda item: print(item))
# 1
# 2
# 3
Parameters
  • func (typeshed.Callable[[Item], None]): The function to call on each item in the iterator.
async def async_for_each( self, func: collections.abc.Callable[[~Item], collections.abc.Coroutine[None, None, None]]) -> None:
476    async def async_for_each(
477        self,
478        func: collections.Callable[[Item], collections.Coroutine[None, None, None]],
479    ) -> None:
480        """Calls the async function on each item in the iterator concurrently.
481
482        Example
483        -------
484        ```py
485        async def signup(username: str) -> None:
486            async with aiohttp.request('POST', '...') as r:
487                # Actual logic.
488                ...
489
490        async def main():
491            users = aiobungie.into_iter(["user_danny", "user_jojo"])
492            await users.async_for_each(lambda username: signup(username))
493        ```
494
495        Parameters
496        ----------
497        func: `collections.Callable[[Item], collections.Coroutine[None, None, None]]`
498            The async function to call on each item in the iterator.
499        """
500        await _helpers.awaits(*(func(item) for item in self))

Calls the async function on each item in the iterator concurrently.

Example
async def signup(username: str) -> None:
    async with aiohttp.request('POST', '...') as r:
        # Actual logic.
        ...

async def main():
    users = aiobungie.into_iter(["user_danny", "user_jojo"])
    await users.async_for_each(lambda username: signup(username))
Parameters
  • func (collections.Callable[[Item], collections.Coroutine[None, None, None]]): The async function to call on each item in the iterator.
def enumerate( self, *, start: int = 0) -> aiobungie.Iterator[tuple[int, ~Item]]:
502    def enumerate(self, *, start: int = 0) -> Iterator[tuple[int, Item]]:
503        """Returns a new iterator that yields tuples of the index and item.
504
505        Example
506        -------
507        ```py
508        iterator = Iterator([1, 2, 3])
509        for index, item in iterator.enumerate():
510            print(index, item)
511        # 0 1
512        # 1 2
513        # 2 3
514        ```
515
516        Raises
517        ------
518        `StopIteration`
519            If no elements are left in the iterator.
520        """
521        return Iterator(enumerate(self._items, start=start))

Returns a new iterator that yields tuples of the index and item.

Example
iterator = Iterator([1, 2, 3])
for index, item in iterator.enumerate():
    print(index, item)
# 0 1
# 1 2
# 2 3
Raises
  • StopIteration: If no elements are left in the iterator.
@typing.final
class MembershipOption(builtins.int, aiobungie.Enum):
710@typing.final
711class MembershipOption(int, Enum):
712    """A enum for GroupV2 membership options."""
713
714    REVIEWD = 0
715    OPEN = 1
716    CLOSED = 2

A enum for GroupV2 membership options.

REVIEWD = <MembershipOption.REVIEWD: 0>
OPEN = <MembershipOption.OPEN: 1>
CLOSED = <MembershipOption.CLOSED: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class MembershipType(builtins.int, aiobungie.Enum):
458@typing.final
459class MembershipType(int, Enum):
460    """An Enum for Bungie membership types."""
461
462    NONE = 0
463    XBOX = 1
464    PSN = 2
465    STEAM = 3
466    BLIZZARD = 4
467    STADIA = 5
468    EPIC_GAMES_STORE = 6
469    DEMON = 10
470    BUNGIE = 254
471    ALL = -1

An Enum for Bungie membership types.

NONE = <MembershipType.NONE: 0>
XBOX = <MembershipType.XBOX: 1>
PSN = <MembershipType.PSN: 2>
STEAM = <MembershipType.STEAM: 3>
BLIZZARD = <MembershipType.BLIZZARD: 4>
STADIA = <MembershipType.STADIA: 5>
EPIC_GAMES_STORE = <MembershipType.EPIC_GAMES_STORE: 6>
DEMON = <MembershipType.DEMON: 10>
BUNGIE = <MembershipType.BUNGIE: 254>
ALL = <MembershipType.ALL: -1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class MembershipTypeError(aiobungie.BadRequest):
182@attrs.define(auto_exc=True)
183class MembershipTypeError(BadRequest):
184    """A bad request error raised when passing wrong membership to the request.
185
186    Those fields are useful since it returns the correct membership and id which can be used
187    to make the request again with those fields.
188
189    Example
190    -------
191    ```py
192    try:
193        profile = await client.fetch_profile(
194            member_id=1,
195            type=aiobungie.MembershipType.STADIA,
196            components=[]
197        )
198
199    # Membership type is wrong!
200    except aiobungie.MembershipTypeError as err:
201        correct_membersip = err.into_membership()
202        profile_id = err.membership_id
203
204        # Recall the method.
205        profile = await client.fetch_profile(
206            member_id=profile_id,
207            type=correct_membership,
208            components=[]
209        )
210    ```
211    """
212
213    membership_type: str
214    """The errored membership type passed to the request."""
215
216    membership_id: int
217    """The errored user's membership id."""
218
219    required_membership: str
220    """The required correct membership for errored user."""
221
222    def into_membership(
223        self, value: typing.Optional[str] = None
224    ) -> enums.MembershipType:
225        """Turn the required membership from `str` into `aiobungie.Membership` type.
226
227        If value parameter is not provided it will fall back to the required membership.
228        """
229        if value is None:
230            return _DETERMINE_MSHIP(self.required_membership)
231        return _DETERMINE_MSHIP(value)
232
233    def __str__(self) -> str:
234        return (
235            f"Expected membership: {self.into_membership().name.replace('_', '').title()}, "
236            f"But got {self.into_membership(self.membership_type)} for id {self.membership_id}"
237        )
238
239    def __int__(self) -> int:
240        return int(self.membership_id)

A bad request error raised when passing wrong membership to the request.

Those fields are useful since it returns the correct membership and id which can be used to make the request again with those fields.

Example
try:
    profile = await client.fetch_profile(
        member_id=1,
        type=aiobungie.MembershipType.STADIA,
        components=[]
    )

# Membership type is wrong!
except aiobungie.MembershipTypeError as err:
    correct_membersip = err.into_membership()
    profile_id = err.membership_id

    # Recall the method.
    profile = await client.fetch_profile(
        member_id=profile_id,
        type=correct_membership,
        components=[]
    )
MembershipTypeError( message: str, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], membership_type: str, membership_id: int, required_membership: str)
 2def __init__(self, message, url, body, headers, membership_type, membership_id, required_membership):
 3    self.message = message
 4    self.url = url
 5    self.body = body
 6    self.headers = headers
 7    self.http_status = attr_dict['http_status'].default
 8    self.membership_type = membership_type
 9    self.membership_id = membership_id
10    self.required_membership = required_membership
11    BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.membership_type,self.membership_id,self.required_membership)

Method generated by attrs for class MembershipTypeError.

membership_type: str

The errored membership type passed to the request.

membership_id: int

The errored user's membership id.

required_membership: str

The required correct membership for errored user.

def into_membership( self, value: Optional[str] = None) -> aiobungie.MembershipType:
222    def into_membership(
223        self, value: typing.Optional[str] = None
224    ) -> enums.MembershipType:
225        """Turn the required membership from `str` into `aiobungie.Membership` type.
226
227        If value parameter is not provided it will fall back to the required membership.
228        """
229        if value is None:
230            return _DETERMINE_MSHIP(self.required_membership)
231        return _DETERMINE_MSHIP(value)

Turn the required membership from str into aiobungie.Membership type.

If value parameter is not provided it will fall back to the required membership.

Inherited Members
BadRequest
url
body
headers
http_status
HTTPError
message
builtins.BaseException
with_traceback
@typing.final
class MilestoneType(builtins.int, aiobungie.Enum):
503@typing.final
504class MilestoneType(int, Enum):
505    """An Enum for Destiny 2 milestone types."""
506
507    UNKNOWN = 0
508    TUTORIAL = 1
509    ONETIME = 2
510    WEEKLY = 3
511    DAILY = 4
512    SPECIAL = 5

An Enum for Destiny 2 milestone types.

UNKNOWN = <MilestoneType.UNKNOWN: 0>
TUTORIAL = <MilestoneType.TUTORIAL: 1>
ONETIME = <MilestoneType.ONETIME: 2>
WEEKLY = <MilestoneType.WEEKLY: 3>
DAILY = <MilestoneType.DAILY: 4>
SPECIAL = <MilestoneType.SPECIAL: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class NotFound(aiobungie.HTTPException):
146@attrs.define(auto_exc=True)
147class NotFound(HTTPException):
148    """Raised when an unknown resource was not found."""
149
150    http_status: http.HTTPStatus = attrs.field(
151        default=http.HTTPStatus.NOT_FOUND, init=False
152    )

Raised when an unknown resource was not found.

NotFound( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class NotFound.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
@typing.final
class ObjectiveUIStyle(builtins.int, aiobungie.Enum):
 94@typing.final
 95class ObjectiveUIStyle(int, enums.Enum):
 96    NONE = 0
 97    HIGHLIGHTED = 1
 98    CRAFTING_WEAPON_LEVEL = 2
 99    CRAFTING_WEAPON_LEVEL_PROGRESS = 3
100    CRAFTING_WEAPON_TIMESTAMP = 4
101    CRAFTING_MEMENTOS = 5
102    CRAFTING_MEMENTO_TITLE = 6

An enumeration.

NONE = <ObjectiveUIStyle.NONE: 0>
HIGHLIGHTED = <ObjectiveUIStyle.HIGHLIGHTED: 1>
CRAFTING_WEAPON_LEVEL = <ObjectiveUIStyle.CRAFTING_WEAPON_LEVEL: 2>
CRAFTING_WEAPON_LEVEL_PROGRESS = <ObjectiveUIStyle.CRAFTING_WEAPON_LEVEL_PROGRESS: 3>
CRAFTING_WEAPON_TIMESTAMP = <ObjectiveUIStyle.CRAFTING_WEAPON_TIMESTAMP: 4>
CRAFTING_MEMENTOS = <ObjectiveUIStyle.CRAFTING_MEMENTOS: 5>
CRAFTING_MEMENTO_TITLE = <ObjectiveUIStyle.CRAFTING_MEMENTO_TITLE: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Place(builtins.int, aiobungie.Enum):
230@typing.final
231class Place(int, Enum):
232    """An Enum for Destiny 2 Places and NOT Planets"""
233
234    ORBIT = 2961497387
235    SOCIAL = 4151112093
236    LIGHT_HOUSE = 4276116472
237    EXPLORE = 3497767639

An Enum for Destiny 2 Places and NOT Planets

ORBIT = <Place.ORBIT: 2961497387>
SOCIAL = <Place.SOCIAL: 4151112093>
LIGHT_HOUSE = <Place.LIGHT_HOUSE: 4276116472>
EXPLORE = <Place.EXPLORE: 3497767639>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Planet(builtins.int, aiobungie.Enum):
195@typing.final
196class Planet(int, Enum):
197    """An Enum for all available planets in Destiny 2."""
198
199    UNKNOWN = 0
200    """Unknown space"""
201
202    EARTH = 3747705955
203    """Earth"""
204
205    DREAMING_CITY = 2877881518
206    """The Dreaming city."""
207
208    NESSUS = 3526908984
209    """Nessus"""
210
211    MOON = 3325508439
212    """The Moon"""
213
214    COSMODROME = 3990611421
215    """The Cosmodrome"""
216
217    TANGLED_SHORE = 3821439926
218    """The Tangled Shore"""
219
220    VENUS = 3871070152
221    """Venus"""
222
223    EAZ = 541863059  # Exclusive event.
224    """European Aerial Zone"""
225
226    EUROPA = 1729879943
227    """Europa"""

An Enum for all available planets in Destiny 2.

UNKNOWN = <Planet.UNKNOWN: 0>

Unknown space

EARTH = <Planet.EARTH: 3747705955>

Earth

DREAMING_CITY = <Planet.DREAMING_CITY: 2877881518>

The Dreaming city.

NESSUS = <Planet.NESSUS: 3526908984>

Nessus

MOON = <Planet.MOON: 3325508439>

The Moon

COSMODROME = <Planet.COSMODROME: 3990611421>

The Cosmodrome

TANGLED_SHORE = <Planet.TANGLED_SHORE: 3821439926>

The Tangled Shore

VENUS = <Planet.VENUS: 3871070152>

Venus

EAZ = <Planet.EAZ: 541863059>

European Aerial Zone

EUROPA = <Planet.EUROPA: 1729879943>

Europa

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Presence(builtins.int, aiobungie.Enum):
680@typing.final
681class Presence(int, Enum):
682    """An enum for a bungie friend status."""
683
684    OFFLINE_OR_UNKNOWN = 0
685    ONLINE = 1

An enum for a bungie friend status.

OFFLINE_OR_UNKNOWN = <Presence.OFFLINE_OR_UNKNOWN: 0>
ONLINE = <Presence.ONLINE: 1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class PrivacySetting(builtins.int, aiobungie.Enum):
768@typing.final
769class PrivacySetting(int, Enum):
770    """An enum for players's privacy settings."""
771
772    OPEN = 0
773    CLAN_AND_FRIENDS = 1
774    FRIENDS_ONLY = 2
775    INVITE_ONLY = 3
776    CLOSED = 4

An enum for players's privacy settings.

OPEN = <PrivacySetting.OPEN: 0>
CLAN_AND_FRIENDS = <PrivacySetting.CLAN_AND_FRIENDS: 1>
FRIENDS_ONLY = <PrivacySetting.FRIENDS_ONLY: 2>
INVITE_ONLY = <PrivacySetting.INVITE_ONLY: 3>
CLOSED = <PrivacySetting.CLOSED: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class RESTClient(aiobungie.interfaces.rest.RESTInterface):
 313class RESTClient(interfaces.RESTInterface):
 314    """A RESTful client implementation for Bungie's API.
 315
 316    This client is designed to only make HTTP requests and return JSON objects
 317    to provide RESTful functionality.
 318
 319    This client is also used within `aiobungie.Client` which deserialize those returned JSON objects
 320    using the factory into Pythonic data classes objects which provide Python functionality.
 321
 322    Example
 323    -------
 324    ```py
 325    import aiobungie
 326
 327    async def main():
 328        async with aiobungie.RESTClient("TOKEN") as rest_client:
 329            req = await rest_client.fetch_clan_members(4389205)
 330            clan_members = req['results']
 331            for member in clan_members:
 332                for k, v in member['destinyUserInfo'].items():
 333                    print(k, v)
 334    ```
 335
 336    Parameters
 337    ----------
 338    token : `str`
 339        A valid application token from Bungie's developer portal.
 340
 341    Other Parameters
 342    ----------------
 343    max_retries : `int`
 344        The max retries number to retry if the request hit a `5xx` status code.
 345    client_secret : `typing.Optional[str]`
 346        An optional application client secret,
 347        This is only needed if you're fetching OAuth2 tokens with this client.
 348    client_id : `typing.Optional[int]`
 349        An optional application client id,
 350        This is only needed if you're fetching OAuth2 tokens with this client.
 351    enable_debugging : `bool | str`
 352        Whether to enable logging responses or not.
 353
 354    Logging Levels
 355    --------------
 356    * `False`: This will disable logging.
 357    * `True`: This will set the level to `DEBUG` and enable logging minimal information.
 358    * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information.
 359    """
 360
 361    __slots__ = (
 362        "_token",
 363        "_session",
 364        "_lock",
 365        "_max_retries",
 366        "_client_secret",
 367        "_client_id",
 368        "_metadata",
 369    )
 370
 371    def __init__(
 372        self,
 373        token: str,
 374        /,
 375        *,
 376        client_secret: typing.Optional[str] = None,
 377        client_id: typing.Optional[int] = None,
 378        client_session: typing.Optional[aiohttp.ClientSession] = None,
 379        max_retries: int = 4,
 380        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
 381    ) -> None:
 382        self._session: typing.Optional[aiohttp.ClientSession] = client_session
 383        self._lock: typing.Optional[asyncio.Lock] = None
 384        self._client_secret = client_secret
 385        self._client_id = client_id
 386        self._token: str = token
 387        self._max_retries = max_retries
 388        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
 389
 390        self._set_debug_level(enable_debugging)
 391
 392    @property
 393    def client_id(self) -> typing.Optional[int]:
 394        return self._client_id
 395
 396    @property
 397    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
 398        return self._metadata
 399
 400    @property
 401    def is_alive(self) -> bool:
 402        return self._session is not None
 403
 404    @typing.final
 405    async def close(self) -> None:
 406        if self._session is None:
 407            raise RuntimeError("REST client is not running.")
 408
 409        await self._session.close()
 410        self._session = None
 411
 412    @typing.final
 413    def open(self) -> None:
 414        """Open a new client session. This is called internally with contextmanager usage."""
 415        if self._session:
 416            raise RuntimeError("Cannot open REST client when it's already open.")
 417
 418        self._session = aiohttp.ClientSession(
 419            connector=aiohttp.TCPConnector(ssl=False),
 420            raise_for_status=False,
 421            timeout=aiohttp.ClientTimeout(total=30.0),
 422        )
 423
 424    @typing.final
 425    def enable_debugging(
 426        self,
 427        level: typing.Union[typing.Literal["TRACE"], bool, int] = False,
 428        file: typing.Optional[typing.Union[pathlib.Path, str]] = None,
 429        /,
 430    ) -> None:
 431        self._set_debug_level(level, file)
 432
 433    @typing.final
 434    async def static_request(
 435        self,
 436        method: typing.Union[RequestMethod, str],
 437        path: str,
 438        *,
 439        auth: typing.Optional[str] = None,
 440        json: typing.Optional[dict[str, typing.Any]] = None,
 441    ) -> ResponseSig:
 442        return await self._request(method, path, auth=auth, json=json)
 443
 444    @typing.final
 445    def build_oauth2_url(
 446        self, client_id: typing.Optional[int] = None
 447    ) -> typing.Optional[builders.OAuthURL]:
 448        client_id = client_id or self._client_id
 449        if client_id is None:
 450            return None
 451
 452        return builders.OAuthURL(client_id=client_id)
 453
 454    @staticmethod
 455    def _set_debug_level(
 456        level: typing.Union[typing.Literal["TRACE"], bool, int] = False,
 457        file: typing.Optional[typing.Union[pathlib.Path, str]] = None,
 458    ) -> None:
 459
 460        file_handler = logging.FileHandler(file, mode="w") if file else None
 461        if level == "TRACE" or level == TRACE:
 462            logging.basicConfig(
 463                level=TRACE, handlers=[file_handler] if file_handler else None
 464            )
 465
 466        elif level:
 467            logging.basicConfig(
 468                level=logging.DEBUG, handlers=[file_handler] if file_handler else None
 469            )
 470
 471    async def _request(
 472        self,
 473        method: typing.Union[RequestMethod, str],
 474        route: str,
 475        *,
 476        base: bool = False,
 477        oauth2: bool = False,
 478        auth: typing.Optional[str] = None,
 479        unwrapping: typing.Literal["json", "read"] = "json",
 480        json: typing.Optional[dict[str, typing.Any]] = None,
 481        headers: typing.Optional[dict[str, typing.Any]] = None,
 482        data: typing.Optional[typing.Union[str, dict[str, typing.Any]]] = None,
 483    ) -> ResponseSig:
 484
 485        # This is not None when opening the client.
 486        assert self._session is not None
 487
 488        retries: int = 0
 489        headers = headers or {}
 490
 491        headers.setdefault(_USER_AGENT_HEADERS, _USER_AGENT)
 492        headers["X-API-KEY"] = self._token
 493
 494        if auth is not None:
 495            headers[_AUTH_HEADER] = f"Bearer {auth}"
 496
 497        # Handling endpoints
 498        endpoint = url.BASE
 499
 500        if not base:
 501            endpoint = endpoint + url.REST_EP
 502
 503        if oauth2:
 504            headers["Content-Type"] = "application/x-www-form-urlencoded"
 505            endpoint = endpoint + url.TOKEN_EP
 506
 507        if self._lock is None:
 508            self._lock = asyncio.Lock()
 509
 510        while True:
 511            async with (stack := contextlib.AsyncExitStack()):
 512                await stack.enter_async_context(self._lock)
 513
 514                # We make the request here.
 515                taken_time = time.monotonic()
 516                response = await stack.enter_async_context(
 517                    self._session.request(
 518                        method=method,
 519                        url=f"{endpoint}/{route}",
 520                        json=json,
 521                        headers=headers,
 522                        data=data,
 523                    )
 524                )
 525                response_time = (time.monotonic() - taken_time) * 1_000
 526
 527                _LOG.debug(
 528                    "%s %s %s Time %.4fms",
 529                    method,
 530                    f"{endpoint}/{route}",
 531                    f"{response.status} {response.reason}",
 532                    response_time,
 533                )
 534
 535                await self._handle_ratelimit(response, method, route)
 536
 537                if response.status == http.HTTPStatus.NO_CONTENT:
 538                    return None
 539
 540                if 300 > response.status >= 200:
 541                    if unwrapping == "read":
 542                        # We need to read the bytes for the manifest response.
 543                        return await response.read()
 544
 545                    if response.content_type == _APP_JSON:
 546                        json_data = await response.json()
 547
 548                        _LOG.debug(
 549                            "%s %s %s Time %.4fms",
 550                            method,
 551                            f"{endpoint}/{route}",
 552                            f"{response.status} {response.reason}",
 553                            response_time,
 554                        )
 555
 556                        if _LOG.isEnabledFor(TRACE):
 557                            cloned = headers.copy()
 558                            cloned.update(response.headers)  # type: ignore
 559
 560                            _LOG.log(
 561                                TRACE,
 562                                "%s",
 563                                error.stringify_http_message(cloned),
 564                            )
 565
 566                        # Return the response.
 567                        # oauth2 responses are not packed inside a Response object.
 568                        if oauth2:
 569                            return json_data  # type: ignore[no-any-return]
 570
 571                        return json_data["Response"]  # type: ignore[no-any-return]
 572
 573                if (
 574                    response.status in _RETRY_5XX
 575                    and retries < self._max_retries  # noqa: W503
 576                ):
 577                    backoff_ = backoff.ExponentialBackOff(maximum=6)
 578                    sleep_time = next(backoff_)
 579                    _LOG.warning(
 580                        "Got %i - %s. Sleeping for %.2f seconds. Remaining retries: %i",
 581                        response.status,
 582                        response.reason,
 583                        sleep_time,
 584                        self._max_retries - retries,
 585                    )
 586
 587                    retries += 1
 588                    await asyncio.sleep(sleep_time)
 589                    continue
 590
 591                raise await error.raise_error(response)
 592
 593    if not typing.TYPE_CHECKING:
 594
 595        def __enter__(self) -> typing.NoReturn:
 596            cls = type(self)
 597            raise TypeError(
 598                f"{cls.__qualname__} is async only, use 'async with' instead."
 599            )
 600
 601        def __exit__(
 602            self,
 603            exception_type: typing.Optional[type[BaseException]],
 604            exception: typing.Optional[BaseException],
 605            exception_traceback: typing.Optional[types.TracebackType],
 606        ) -> None:
 607            ...
 608
 609    async def __aenter__(self) -> RESTClient:
 610        self.open()
 611        return self
 612
 613    async def __aexit__(
 614        self,
 615        exception_type: typing.Optional[type[BaseException]],
 616        exception: typing.Optional[BaseException],
 617        exception_traceback: typing.Optional[types.TracebackType],
 618    ) -> None:
 619        await self.close()
 620
 621    # We don't want this to be super complicated.
 622    @typing.final
 623    async def _handle_ratelimit(
 624        self,
 625        response: aiohttp.ClientResponse,
 626        method: str,
 627        route: str,
 628    ) -> None:
 629
 630        if response.status != http.HTTPStatus.TOO_MANY_REQUESTS:
 631            return
 632
 633        if response.content_type != _APP_JSON:
 634            raise error.HTTPError(
 635                f"Being ratelimited on non JSON request, {response.content_type}.",
 636                http.HTTPStatus.TOO_MANY_REQUESTS,
 637            )
 638
 639        json: typedefs.JSONObject = await response.json()
 640        retry_after = float(json.get("ThrottleSeconds", 15.0)) + 0.1
 641        max_calls: int = 0
 642
 643        while True:
 644            if max_calls == 10:
 645                # Max retries by default. We raise an error here.
 646                raise error.RateLimitedError(
 647                    body=json,
 648                    url=str(response.real_url),
 649                    retry_after=retry_after,
 650                )
 651
 652            # We sleep for a little bit to avoid funky behavior.
 653            _LOG.warning(
 654                "We're being ratelimited, Method %s Route %s. Sleeping for %.2fs.",
 655                method,
 656                route,
 657                retry_after,
 658            )
 659            await asyncio.sleep(retry_after)
 660            max_calls += 1
 661            continue
 662
 663    async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response:
 664        if not isinstance(self._client_secret, (str, int)):
 665            raise TypeError(
 666                "Expected (str, int) for client secret "
 667                f"but got {type(self._client_secret).__name__}"  # type: ignore
 668            )
 669
 670        headers = {
 671            "client_secret": self._client_secret,
 672        }
 673
 674        data = (
 675            f"grant_type=authorization_code&code={code}"
 676            f"&client_id={self._client_id}&client_secret={self._client_secret}"
 677        )
 678
 679        response = await self._request(
 680            RequestMethod.POST, "", headers=headers, data=data, oauth2=True
 681        )
 682        assert isinstance(response, dict)
 683        return builders.OAuth2Response.build_response(response)
 684
 685    async def refresh_access_token(
 686        self, refresh_token: str, /
 687    ) -> builders.OAuth2Response:
 688        if not isinstance(self._client_secret, (int, str)):
 689            raise TypeError(
 690                f"Expected (str, int) for client secret but got {type(self._client_secret).__name__}"  # type: ignore
 691            )
 692
 693        data = {
 694            "grant_type": "refresh_token",
 695            "refresh_token": refresh_token,
 696            "client_id": self._client_id,
 697            "client_secret": self._client_secret,
 698            "Content-Type": "application/x-www-form-urlencoded",
 699        }
 700
 701        response = await self._request(RequestMethod.POST, "", data=data, oauth2=True)
 702        assert isinstance(response, dict)
 703        return builders.OAuth2Response.build_response(response)
 704
 705    async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject:
 706        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 707        resp = await self._request(
 708            RequestMethod.GET, f"User/GetBungieNetUserById/{id}/"
 709        )
 710        assert isinstance(resp, dict)
 711        return resp
 712
 713    async def fetch_user_themes(self) -> typedefs.JSONArray:
 714        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 715        resp = await self._request(RequestMethod.GET, "User/GetAvailableThemes/")
 716        assert isinstance(resp, list)
 717        return resp
 718
 719    async def fetch_membership_from_id(
 720        self,
 721        id: int,
 722        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 723        /,
 724    ) -> typedefs.JSONObject:
 725        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 726        resp = await self._request(
 727            RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}"
 728        )
 729        assert isinstance(resp, dict)
 730        return resp
 731
 732    async def fetch_player(
 733        self,
 734        name: str,
 735        code: int,
 736        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
 737        /,
 738    ) -> typedefs.JSONArray:
 739        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 740        resp = await self._request(
 741            RequestMethod.POST,
 742            f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}",
 743            json={"displayName": name, "displayNameCode": code},
 744        )
 745        assert isinstance(resp, list)
 746        return resp
 747
 748    async def search_users(self, name: str, /) -> typedefs.JSONObject:
 749        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 750        resp = await self._request(
 751            RequestMethod.POST,
 752            "User/Search/GlobalName/0",
 753            json={"displayNamePrefix": name},
 754        )
 755        assert isinstance(resp, dict)
 756        return resp
 757
 758    async def fetch_clan_from_id(
 759        self, id: int, /, access_token: typing.Optional[str] = None
 760    ) -> typedefs.JSONObject:
 761        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 762        resp = await self._request(
 763            RequestMethod.GET, f"GroupV2/{id}", auth=access_token
 764        )
 765        assert isinstance(resp, dict)
 766        return resp
 767
 768    async def fetch_clan(
 769        self,
 770        name: str,
 771        /,
 772        access_token: typing.Optional[str] = None,
 773        *,
 774        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 775    ) -> typedefs.JSONObject:
 776        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 777        resp = await self._request(
 778            RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token
 779        )
 780        assert isinstance(resp, dict)
 781        return resp
 782
 783    async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject:
 784        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 785        resp = await self._request(
 786            RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/"
 787        )
 788        assert isinstance(resp, dict)
 789        return resp
 790
 791    async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray:
 792        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 793        resp = await self._request(
 794            RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/"
 795        )
 796        assert isinstance(resp, list)
 797        return resp
 798
 799    async def fetch_application(self, appid: int, /) -> typedefs.JSONObject:
 800        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 801        resp = await self._request(RequestMethod.GET, f"App/Application/{appid}")
 802        assert isinstance(resp, dict)
 803        return resp
 804
 805    async def fetch_character(
 806        self,
 807        member_id: int,
 808        membership_type: typedefs.IntAnd[enums.MembershipType],
 809        character_id: int,
 810        components: list[enums.ComponentType],
 811        auth: typing.Optional[str] = None,
 812    ) -> typedefs.JSONObject:
 813        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 814        collector = _collect_components(components)
 815        response = await self._request(
 816            RequestMethod.GET,
 817            f"Destiny2/{int(membership_type)}/Profile/{member_id}/"
 818            f"Character/{character_id}/?components={collector}",
 819            auth=auth,
 820        )
 821        assert isinstance(response, dict)
 822        return response
 823
 824    async def fetch_activities(
 825        self,
 826        member_id: int,
 827        character_id: int,
 828        mode: typedefs.IntAnd[enums.GameMode],
 829        membership_type: typedefs.IntAnd[
 830            enums.MembershipType
 831        ] = enums.MembershipType.ALL,
 832        *,
 833        page: int = 0,
 834        limit: int = 1,
 835    ) -> typedefs.JSONObject:
 836        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 837        resp = await self._request(
 838            RequestMethod.GET,
 839            f"Destiny2/{int(membership_type)}/Account/"
 840            f"{member_id}/Character/{character_id}/Stats/Activities"
 841            f"/?mode={int(mode)}&count={limit}&page={page}",
 842        )
 843        assert isinstance(resp, dict)
 844        return resp
 845
 846    async def fetch_vendor_sales(self) -> typedefs.JSONObject:
 847        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 848        resp = await self._request(
 849            RequestMethod.GET,
 850            f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}",
 851        )
 852        assert isinstance(resp, dict)
 853        return resp
 854
 855    async def fetch_profile(
 856        self,
 857        membership_id: int,
 858        type: typedefs.IntAnd[enums.MembershipType],
 859        components: list[enums.ComponentType],
 860        auth: typing.Optional[str] = None,
 861    ) -> typedefs.JSONObject:
 862        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 863        collector = _collect_components(components)
 864        response = await self._request(
 865            RequestMethod.GET,
 866            f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}",
 867            auth=auth,
 868        )
 869        assert isinstance(response, dict)
 870        return response
 871
 872    async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject:
 873        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 874        response = await self._request(
 875            RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}"
 876        )
 877        assert isinstance(response, dict)
 878        return response
 879
 880    async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject:
 881        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 882        resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash)
 883        assert isinstance(resp, dict)
 884        return resp
 885
 886    async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject:
 887        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 888        resp = await self.fetch_entity("DestinyObjectiveDefinition", hash)
 889        assert isinstance(resp, dict)
 890        return resp
 891
 892    async def fetch_groups_for_member(
 893        self,
 894        member_id: int,
 895        member_type: typedefs.IntAnd[enums.MembershipType],
 896        /,
 897        *,
 898        filter: int = 0,
 899        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 900    ) -> typedefs.JSONObject:
 901        resp = await self._request(
 902            RequestMethod.GET,
 903            f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
 904        )
 905        assert isinstance(resp, dict)
 906        return resp
 907
 908    async def fetch_potential_groups_for_member(
 909        self,
 910        member_id: int,
 911        member_type: typedefs.IntAnd[enums.MembershipType],
 912        /,
 913        *,
 914        filter: int = 0,
 915        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 916    ) -> typedefs.JSONObject:
 917        resp = await self._request(
 918            RequestMethod.GET,
 919            f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
 920        )
 921        assert isinstance(resp, dict)
 922        return resp
 923
 924    async def fetch_clan_members(
 925        self,
 926        clan_id: int,
 927        /,
 928        *,
 929        name: typing.Optional[str] = None,
 930        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 931    ) -> typedefs.JSONObject:
 932        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 933        resp = await self._request(
 934            RequestMethod.GET,
 935            f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}&currentpage=1",
 936        )
 937        assert isinstance(resp, dict)
 938        return resp
 939
 940    async def fetch_hardlinked_credentials(
 941        self,
 942        credential: int,
 943        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
 944        /,
 945    ) -> typedefs.JSONObject:
 946        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 947        resp = await self._request(
 948            RequestMethod.GET,
 949            f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/",
 950        )
 951        assert isinstance(resp, dict)
 952        return resp
 953
 954    async def fetch_user_credentials(
 955        self, access_token: str, membership_id: int, /
 956    ) -> typedefs.JSONArray:
 957        resp = await self._request(
 958            RequestMethod.GET,
 959            f"User/GetCredentialTypesForTargetAccount/{membership_id}",
 960            auth=access_token,
 961        )
 962        assert isinstance(resp, list)
 963        return resp
 964
 965    async def insert_socket_plug(
 966        self,
 967        action_token: str,
 968        /,
 969        instance_id: int,
 970        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
 971        character_id: int,
 972        membership_type: typedefs.IntAnd[enums.MembershipType],
 973    ) -> typedefs.JSONObject:
 974
 975        if isinstance(plug, builders.PlugSocketBuilder):
 976            plug = plug.collect()
 977
 978        body = {
 979            "actionToken": action_token,
 980            "itemInstanceId": instance_id,
 981            "plug": plug,
 982            "characterId": character_id,
 983            "membershipType": int(membership_type),
 984        }
 985        resp = await self._request(
 986            RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body
 987        )
 988        assert isinstance(resp, dict)
 989        return resp
 990
 991    async def insert_socket_plug_free(
 992        self,
 993        access_token: str,
 994        /,
 995        instance_id: int,
 996        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
 997        character_id: int,
 998        membership_type: typedefs.IntAnd[enums.MembershipType],
 999    ) -> typedefs.JSONObject:
1000
1001        if isinstance(plug, builders.PlugSocketBuilder):
1002            plug = plug.collect()
1003
1004        body = {
1005            "itemInstanceId": instance_id,
1006            "plug": plug,
1007            "characterId": character_id,
1008            "membershipType": int(membership_type),
1009        }
1010        resp = await self._request(
1011            RequestMethod.POST,
1012            "Destiny2/Actions/Items/InsertSocketPlugFree",
1013            json=body,
1014            auth=access_token,
1015        )
1016        assert isinstance(resp, dict)
1017        return resp
1018
1019    async def set_item_lock_state(
1020        self,
1021        access_token: str,
1022        state: bool,
1023        /,
1024        item_id: int,
1025        character_id: int,
1026        membership_type: typedefs.IntAnd[enums.MembershipType],
1027    ) -> int:
1028        body = {
1029            "state": state,
1030            "itemId": item_id,
1031            "characterId": character_id,
1032            "membership_type": int(membership_type),
1033        }
1034        response = await self._request(
1035            RequestMethod.POST,
1036            "Destiny2/Actions/Items/SetLockState",
1037            json=body,
1038            auth=access_token,
1039        )
1040        assert isinstance(response, int)
1041        return response
1042
1043    async def set_quest_track_state(
1044        self,
1045        access_token: str,
1046        state: bool,
1047        /,
1048        item_id: int,
1049        character_id: int,
1050        membership_type: typedefs.IntAnd[enums.MembershipType],
1051    ) -> int:
1052        body = {
1053            "state": state,
1054            "itemId": item_id,
1055            "characterId": character_id,
1056            "membership_type": int(membership_type),
1057        }
1058        response = await self._request(
1059            RequestMethod.POST,
1060            "Destiny2/Actions/Items/SetTrackedState",
1061            json=body,
1062            auth=access_token,
1063        )
1064        assert isinstance(response, int)
1065        return response
1066
1067    async def fetch_manifest_path(self) -> typedefs.JSONObject:
1068        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1069        path = await self._request(RequestMethod.GET, "Destiny2/Manifest")
1070        assert isinstance(path, dict)
1071        return path
1072
1073    async def read_manifest_bytes(self, language: str = "en", /) -> bytes:
1074        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1075        _ensure_manifest_language(language)
1076
1077        content = await self.fetch_manifest_path()
1078        resp = await self._request(
1079            RequestMethod.GET,
1080            content["mobileWorldContentPaths"][language],
1081            unwrapping="read",
1082            base=True,
1083        )
1084        assert isinstance(resp, bytes)
1085        return resp
1086
1087    async def download_manifest(
1088        self,
1089        language: str = "en",
1090        name: str = "manifest",
1091        path: typing.Union[pathlib.Path, str] = ".",
1092        *,
1093        force: bool = False,
1094    ) -> None:
1095        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1096        complete_path = _get_path(name, path, sql=True)
1097
1098        if complete_path.exists() and force:
1099            if force:
1100                _LOG.info(
1101                    f"Found manifest in {complete_path!s}. Forcing to Re-Download."
1102                )
1103                complete_path.unlink(missing_ok=True)
1104
1105                return await self.download_manifest(language, name, path, force=force)
1106
1107            else:
1108                raise FileExistsError(
1109                    "Manifest file already exists, "
1110                    "To force download, set the `force` parameter to `True`."
1111                )
1112
1113        _LOG.info(f"Downloading manifest. Location: {complete_path!s}")
1114        data_bytes = await self.read_manifest_bytes(language)
1115        await asyncio.get_running_loop().run_in_executor(
1116            None, _write_sqlite_bytes, data_bytes, path, name
1117        )
1118
1119    async def download_json_manifest(
1120        self,
1121        file_name: str = "manifest",
1122        path: typing.Union[str, pathlib.Path] = ".",
1123        language: str = "en",
1124    ) -> None:
1125        _ensure_manifest_language(language)
1126
1127        _LOG.info(f"Downloading manifest JSON to {_get_path(file_name, path)!r}...")
1128
1129        content = await self.fetch_manifest_path()
1130        json_bytes = await self._request(
1131            RequestMethod.GET,
1132            content["jsonWorldContentPaths"][language],
1133            unwrapping="read",
1134            base=True,
1135        )
1136
1137        await asyncio.get_running_loop().run_in_executor(
1138            None, _write_json_bytes, json_bytes, file_name, path
1139        )
1140        _LOG.info("Finished downloading manifest JSON.")
1141
1142    async def fetch_manifest_version(self) -> str:
1143        return typing.cast(str, (await self.fetch_manifest_path())["version"])
1144
1145    async def fetch_linked_profiles(
1146        self,
1147        member_id: int,
1148        member_type: typedefs.IntAnd[enums.MembershipType],
1149        /,
1150        *,
1151        all: bool = False,
1152    ) -> typedefs.JSONObject:
1153        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1154        resp = await self._request(
1155            RequestMethod.GET,
1156            f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}",
1157        )
1158        assert isinstance(resp, dict)
1159        return resp
1160
1161    async def fetch_clan_banners(self) -> typedefs.JSONObject:
1162        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1163        resp = await self._request(
1164            RequestMethod.GET, "Destiny2/Clan/ClanBannerDictionary/"
1165        )
1166        assert isinstance(resp, dict)
1167        return resp
1168
1169    async def fetch_public_milestones(self) -> typedefs.JSONObject:
1170        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1171        resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/")
1172        assert isinstance(resp, dict)
1173        return resp
1174
1175    async def fetch_public_milestone_content(
1176        self, milestone_hash: int, /
1177    ) -> typedefs.JSONObject:
1178        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1179        resp = await self._request(
1180            RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/"
1181        )
1182        assert isinstance(resp, dict)
1183        return resp
1184
1185    async def fetch_current_user_memberships(
1186        self, access_token: str, /
1187    ) -> typedefs.JSONObject:
1188        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1189        resp = await self._request(
1190            RequestMethod.GET,
1191            "User/GetMembershipsForCurrentUser/",
1192            auth=access_token,
1193        )
1194        assert isinstance(resp, dict)
1195        return resp
1196
1197    async def equip_item(
1198        self,
1199        access_token: str,
1200        /,
1201        item_id: int,
1202        character_id: int,
1203        membership_type: typedefs.IntAnd[enums.MembershipType],
1204    ) -> None:
1205        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1206        payload = {
1207            "itemId": item_id,
1208            "characterId": character_id,
1209            "membershipType": int(membership_type),
1210        }
1211
1212        await self._request(
1213            RequestMethod.POST,
1214            "Destiny2/Actions/Items/EquipItem/",
1215            json=payload,
1216            auth=access_token,
1217        )
1218
1219    async def equip_items(
1220        self,
1221        access_token: str,
1222        /,
1223        item_ids: list[int],
1224        character_id: int,
1225        membership_type: typedefs.IntAnd[enums.MembershipType],
1226    ) -> None:
1227        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1228        payload = {
1229            "itemIds": item_ids,
1230            "characterId": character_id,
1231            "membershipType": int(membership_type),
1232        }
1233        await self._request(
1234            RequestMethod.POST,
1235            "Destiny2/Actions/Items/EquipItems/",
1236            json=payload,
1237            auth=access_token,
1238        )
1239
1240    async def ban_clan_member(
1241        self,
1242        access_token: str,
1243        /,
1244        group_id: int,
1245        membership_id: int,
1246        membership_type: typedefs.IntAnd[enums.MembershipType],
1247        *,
1248        length: int = 0,
1249        comment: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1250    ) -> None:
1251        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1252        payload = {"comment": str(comment), "length": length}
1253        await self._request(
1254            RequestMethod.POST,
1255            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/",
1256            json=payload,
1257            auth=access_token,
1258        )
1259
1260    async def unban_clan_member(
1261        self,
1262        access_token: str,
1263        /,
1264        group_id: int,
1265        membership_id: int,
1266        membership_type: typedefs.IntAnd[enums.MembershipType],
1267    ) -> None:
1268        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1269        await self._request(
1270            RequestMethod.POST,
1271            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/",
1272            auth=access_token,
1273        )
1274
1275    async def kick_clan_member(
1276        self,
1277        access_token: str,
1278        /,
1279        group_id: int,
1280        membership_id: int,
1281        membership_type: typedefs.IntAnd[enums.MembershipType],
1282    ) -> typedefs.JSONObject:
1283        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1284        resp = await self._request(
1285            RequestMethod.POST,
1286            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/",
1287            auth=access_token,
1288        )
1289        assert isinstance(resp, dict)
1290        return resp
1291
1292    async def edit_clan(
1293        self,
1294        access_token: str,
1295        /,
1296        group_id: int,
1297        *,
1298        name: typedefs.NoneOr[str] = None,
1299        about: typedefs.NoneOr[str] = None,
1300        motto: typedefs.NoneOr[str] = None,
1301        theme: typedefs.NoneOr[str] = None,
1302        tags: typedefs.NoneOr[collections.Sequence[str]] = None,
1303        is_public: typedefs.NoneOr[bool] = None,
1304        locale: typedefs.NoneOr[str] = None,
1305        avatar_image_index: typedefs.NoneOr[int] = None,
1306        membership_option: typedefs.NoneOr[
1307            typedefs.IntAnd[enums.MembershipOption]
1308        ] = None,
1309        allow_chat: typedefs.NoneOr[bool] = None,
1310        chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None,
1311        call_sign: typedefs.NoneOr[str] = None,
1312        homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1313        enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None,
1314        default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1315        is_public_topic_admin: typedefs.NoneOr[bool] = None,
1316    ) -> None:
1317        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1318        payload = {
1319            "name": name,
1320            "about": about,
1321            "motto": motto,
1322            "theme": theme,
1323            "tags": tags,
1324            "isPublic": is_public,
1325            "avatarImageIndex": avatar_image_index,
1326            "isPublicTopicAdminOnly": is_public_topic_admin,
1327            "allowChat": allow_chat,
1328            "chatSecurity": chat_security,
1329            "callsign": call_sign,
1330            "homepage": homepage,
1331            "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins,
1332            "defaultPublicity": default_publicity,
1333            "locale": locale,
1334        }
1335        if membership_option is not None:
1336            payload["membershipOption"] = int(membership_option)
1337
1338        await self._request(
1339            RequestMethod.POST,
1340            f"GroupV2/{group_id}/Edit",
1341            json=payload,
1342            auth=access_token,
1343        )
1344
1345    async def edit_clan_options(
1346        self,
1347        access_token: str,
1348        /,
1349        group_id: int,
1350        *,
1351        invite_permissions_override: typedefs.NoneOr[bool] = None,
1352        update_culture_permissionOverride: typedefs.NoneOr[bool] = None,
1353        host_guided_game_permission_override: typedefs.NoneOr[
1354            typing.Literal[0, 1, 2]
1355        ] = None,
1356        update_banner_permission_override: typedefs.NoneOr[bool] = None,
1357        join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None,
1358    ) -> None:
1359
1360        payload = {
1361            "InvitePermissionOverride": invite_permissions_override,
1362            "UpdateCulturePermissionOverride": update_culture_permissionOverride,
1363            "HostGuidedGamePermissionOverride": host_guided_game_permission_override,
1364            "UpdateBannerPermissionOverride": update_banner_permission_override,
1365            "JoinLevel": int(join_level) if join_level else None,
1366        }
1367
1368        await self._request(
1369            RequestMethod.POST,
1370            f"GroupV2/{group_id}/EditFounderOptions",
1371            json=payload,
1372            auth=access_token,
1373        )
1374
1375    async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject:
1376        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1377        resp = await self._request(
1378            RequestMethod.GET,
1379            "Social/Friends/",
1380            auth=access_token,
1381        )
1382        assert isinstance(resp, dict)
1383        return resp
1384
1385    async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject:
1386        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1387        resp = await self._request(
1388            RequestMethod.GET,
1389            "Social/Friends/Requests",
1390            auth=access_token,
1391        )
1392        assert isinstance(resp, dict)
1393        return resp
1394
1395    async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1396        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1397        await self._request(
1398            RequestMethod.POST,
1399            f"Social/Friends/Requests/Accept/{member_id}",
1400            auth=access_token,
1401        )
1402
1403    async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1404        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1405        await self._request(
1406            RequestMethod.POST,
1407            f"Social/Friends/Add/{member_id}",
1408            auth=access_token,
1409        )
1410
1411    async def decline_friend_request(
1412        self, access_token: str, /, member_id: int
1413    ) -> None:
1414        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1415        await self._request(
1416            RequestMethod.POST,
1417            f"Social/Friends/Requests/Decline/{member_id}",
1418            auth=access_token,
1419        )
1420
1421    async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1422        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1423        await self._request(
1424            RequestMethod.POST,
1425            f"Social/Friends/Remove/{member_id}",
1426            auth=access_token,
1427        )
1428
1429    async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1430        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1431        await self._request(
1432            RequestMethod.POST,
1433            f"Social/Friends/Requests/Remove/{member_id}",
1434            auth=access_token,
1435        )
1436
1437    async def approve_all_pending_group_users(
1438        self,
1439        access_token: str,
1440        /,
1441        group_id: int,
1442        message: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1443    ) -> None:
1444        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1445        await self._request(
1446            RequestMethod.POST,
1447            f"GroupV2/{group_id}/Members/ApproveAll",
1448            auth=access_token,
1449            json={"message": str(message)},
1450        )
1451
1452    async def deny_all_pending_group_users(
1453        self,
1454        access_token: str,
1455        /,
1456        group_id: int,
1457        *,
1458        message: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1459    ) -> None:
1460        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1461        await self._request(
1462            RequestMethod.POST,
1463            f"GroupV2/{group_id}/Members/DenyAll",
1464            auth=access_token,
1465            json={"message": str(message)},
1466        )
1467
1468    async def add_optional_conversation(
1469        self,
1470        access_token: str,
1471        /,
1472        group_id: int,
1473        *,
1474        name: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1475        security: typing.Literal[0, 1] = 0,
1476    ) -> None:
1477        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1478        payload = {"chatName": str(name), "chatSecurity": security}
1479        await self._request(
1480            RequestMethod.POST,
1481            f"GroupV2/{group_id}/OptionalConversations/Add",
1482            json=payload,
1483            auth=access_token,
1484        )
1485
1486    async def edit_optional_conversation(
1487        self,
1488        access_token: str,
1489        /,
1490        group_id: int,
1491        conversation_id: int,
1492        *,
1493        name: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1494        security: typing.Literal[0, 1] = 0,
1495        enable_chat: bool = False,
1496    ) -> None:
1497        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1498        payload = {
1499            "chatEnabled": enable_chat,
1500            "chatName": str(name),
1501            "chatSecurity": security,
1502        }
1503        await self._request(
1504            RequestMethod.POST,
1505            f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}",
1506            json=payload,
1507            auth=access_token,
1508        )
1509
1510    async def transfer_item(
1511        self,
1512        access_token: str,
1513        /,
1514        item_id: int,
1515        item_hash: int,
1516        character_id: int,
1517        member_type: typedefs.IntAnd[enums.MembershipType],
1518        *,
1519        stack_size: int = 1,
1520        vault: bool = False,
1521    ) -> None:
1522        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1523        payload = {
1524            "characterId": character_id,
1525            "membershipType": int(member_type),
1526            "itemId": item_id,
1527            "itemReferenceHash": item_hash,
1528            "stackSize": stack_size,
1529            "transferToVault": vault,
1530        }
1531        await self._request(
1532            RequestMethod.POST,
1533            "Destiny2/Actions/Items/TransferItem",
1534            json=payload,
1535            auth=access_token,
1536        )
1537
1538    async def pull_item(
1539        self,
1540        access_token: str,
1541        /,
1542        item_id: int,
1543        item_hash: int,
1544        character_id: int,
1545        member_type: typedefs.IntAnd[enums.MembershipType],
1546        *,
1547        stack_size: int = 1,
1548        vault: bool = False,
1549    ) -> None:
1550        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1551        payload = {
1552            "characterId": character_id,
1553            "membershipType": int(member_type),
1554            "itemId": item_id,
1555            "itemReferenceHash": item_hash,
1556            "stackSize": stack_size,
1557            "transferToVault": vault,
1558        }
1559        await self._request(
1560            RequestMethod.POST,
1561            "Destiny2/Actions/Items/PullFromPostmaster",
1562            json=payload,
1563            auth=access_token,
1564        )
1565
1566    async def fetch_fireteams(
1567        self,
1568        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1569        *,
1570        platform: typedefs.IntAnd[
1571            fireteams.FireteamPlatform
1572        ] = fireteams.FireteamPlatform.ANY,
1573        language: typing.Union[
1574            fireteams.FireteamLanguage, str
1575        ] = fireteams.FireteamLanguage.ALL,
1576        date_range: typedefs.IntAnd[
1577            fireteams.FireteamDate
1578        ] = fireteams.FireteamDate.ALL,
1579        page: int = 0,
1580        slots_filter: int = 0,
1581    ) -> typedefs.JSONObject:
1582        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1583        resp = await self._request(
1584            RequestMethod.GET,
1585            f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}",  # noqa: E501 Line too long
1586        )
1587        assert isinstance(resp, dict)
1588        return resp
1589
1590    async def fetch_avaliable_clan_fireteams(
1591        self,
1592        access_token: str,
1593        group_id: int,
1594        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1595        *,
1596        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1597        language: typing.Union[fireteams.FireteamLanguage, str],
1598        date_range: typedefs.IntAnd[
1599            fireteams.FireteamDate
1600        ] = fireteams.FireteamDate.ALL,
1601        page: int = 0,
1602        public_only: bool = False,
1603        slots_filter: int = 0,
1604    ) -> typedefs.JSONObject:
1605        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1606        resp = await self._request(
1607            RequestMethod.GET,
1608            f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}",  # noqa: E501
1609            json={"langFilter": str(language)},
1610            auth=access_token,
1611        )
1612        assert isinstance(resp, dict)
1613        return resp
1614
1615    async def fetch_clan_fireteam(
1616        self, access_token: str, fireteam_id: int, group_id: int
1617    ) -> typedefs.JSONObject:
1618        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1619        resp = await self._request(
1620            RequestMethod.GET,
1621            f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}",
1622            auth=access_token,
1623        )
1624        assert isinstance(resp, dict)
1625        return resp
1626
1627    async def fetch_my_clan_fireteams(
1628        self,
1629        access_token: str,
1630        group_id: int,
1631        *,
1632        include_closed: bool = True,
1633        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1634        language: typing.Union[fireteams.FireteamLanguage, str],
1635        filtered: bool = True,
1636        page: int = 0,
1637    ) -> typedefs.JSONObject:
1638        payload = {"groupFilter": filtered, "langFilter": str(language)}
1639        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1640        resp = await self._request(
1641            RequestMethod.GET,
1642            f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}",
1643            json=payload,
1644            auth=access_token,
1645        )
1646        assert isinstance(resp, dict)
1647        return resp
1648
1649    async def fetch_private_clan_fireteams(
1650        self, access_token: str, group_id: int, /
1651    ) -> int:
1652        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1653        resp = await self._request(
1654            RequestMethod.GET,
1655            f"Fireteam/Clan/{group_id}/ActiveCount",
1656            auth=access_token,
1657        )
1658        assert isinstance(resp, int)
1659        return resp
1660
1661    async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject:
1662        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1663        resp = await self._request(
1664            RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}"
1665        )
1666        assert isinstance(resp, dict)
1667        return resp
1668
1669    async def search_entities(
1670        self, name: str, entity_type: str, *, page: int = 0
1671    ) -> typedefs.JSONObject:
1672        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1673        resp = await self._request(
1674            RequestMethod.GET,
1675            f"Destiny2/Armory/Search/{entity_type}/{name}/",
1676            json={"page": page},
1677        )
1678        assert isinstance(resp, dict)
1679        return resp
1680
1681    async def fetch_unique_weapon_history(
1682        self,
1683        membership_id: int,
1684        character_id: int,
1685        membership_type: typedefs.IntAnd[enums.MembershipType],
1686    ) -> typedefs.JSONObject:
1687        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1688        resp = await self._request(
1689            RequestMethod.GET,
1690            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/",
1691        )
1692        assert isinstance(resp, dict)
1693        return resp
1694
1695    async def fetch_item(
1696        self,
1697        member_id: int,
1698        item_id: int,
1699        membership_type: typedefs.IntAnd[enums.MembershipType],
1700        components: list[enums.ComponentType],
1701    ) -> typedefs.JSONObject:
1702        collector = _collect_components(components)
1703        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1704        resp = await self._request(
1705            RequestMethod.GET,
1706            f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}",
1707        )
1708        assert isinstance(resp, dict)
1709        return resp
1710
1711    async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject:
1712        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1713        resp = await self._request(
1714            RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/"
1715        )
1716        assert isinstance(resp, dict)
1717        return resp
1718
1719    async def fetch_available_locales(self) -> typedefs.JSONObject:
1720        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1721        resp = await self._request(
1722            RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/"
1723        )
1724        assert isinstance(resp, dict)
1725        return resp
1726
1727    async def fetch_common_settings(self) -> typedefs.JSONObject:
1728        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1729        resp = await self._request(RequestMethod.GET, "Settings")
1730        assert isinstance(resp, dict)
1731        return resp
1732
1733    async def fetch_user_systems_overrides(self) -> typedefs.JSONObject:
1734        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1735        resp = await self._request(RequestMethod.GET, "UserSystemOverrides")
1736        assert isinstance(resp, dict)
1737        return resp
1738
1739    async def fetch_global_alerts(
1740        self, *, include_streaming: bool = False
1741    ) -> typedefs.JSONArray:
1742        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1743        resp = await self._request(
1744            RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}"
1745        )
1746        assert isinstance(resp, list)
1747        return resp
1748
1749    async def awainitialize_request(
1750        self,
1751        access_token: str,
1752        type: typing.Literal[0, 1],
1753        membership_type: typedefs.IntAnd[enums.MembershipType],
1754        /,
1755        *,
1756        affected_item_id: typing.Optional[int] = None,
1757        character_id: typing.Optional[int] = None,
1758    ) -> typedefs.JSONObject:
1759        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1760
1761        body = {"type": type, "membershipType": int(membership_type)}
1762
1763        if affected_item_id is not None:
1764            body["affectedItemId"] = affected_item_id
1765
1766        if character_id is not None:
1767            body["characterId"] = character_id
1768
1769        resp = await self._request(
1770            RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token
1771        )
1772        assert isinstance(resp, dict)
1773        return resp
1774
1775    async def awaget_action_token(
1776        self, access_token: str, correlation_id: str, /
1777    ) -> typedefs.JSONObject:
1778        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1779        resp = await self._request(
1780            RequestMethod.POST,
1781            f"Destiny2/Awa/GetActionToken/{correlation_id}",
1782            auth=access_token,
1783        )
1784        assert isinstance(resp, dict)
1785        return resp
1786
1787    async def awa_provide_authorization_result(
1788        self,
1789        access_token: str,
1790        selection: int,
1791        correlation_id: str,
1792        nonce: collections.MutableSequence[typing.Union[str, bytes]],
1793    ) -> int:
1794        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1795
1796        body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce}
1797
1798        resp = await self._request(
1799            RequestMethod.POST,
1800            "Destiny2/Awa/AwaProvideAuthorizationResult",
1801            json=body,
1802            auth=access_token,
1803        )
1804        assert isinstance(resp, int)
1805        return resp
1806
1807    async def fetch_vendors(
1808        self,
1809        access_token: str,
1810        character_id: int,
1811        membership_id: int,
1812        membership_type: typedefs.IntAnd[enums.MembershipType],
1813        /,
1814        components: list[enums.ComponentType],
1815        filter: typing.Optional[int] = None,
1816    ) -> typedefs.JSONObject:
1817        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1818        components_ = _collect_components(components)
1819        route = (
1820            f"Destiny2/{int(membership_type)}/Profile/{membership_id}"
1821            f"/Character/{character_id}/Vendors/?components={components_}"
1822        )
1823
1824        if filter is not None:
1825            route = route + f"&filter={filter}"
1826
1827        resp = await self._request(
1828            RequestMethod.GET,
1829            route,
1830            auth=access_token,
1831        )
1832        assert isinstance(resp, dict)
1833        return resp
1834
1835    async def fetch_vendor(
1836        self,
1837        access_token: str,
1838        character_id: int,
1839        membership_id: int,
1840        membership_type: typedefs.IntAnd[enums.MembershipType],
1841        vendor_hash: int,
1842        /,
1843        components: list[enums.ComponentType],
1844    ) -> typedefs.JSONObject:
1845        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1846        components_ = _collect_components(components)
1847        resp = await self._request(
1848            RequestMethod.GET,
1849            (
1850                f"Platform/Destiny2/{int(membership_type)}/Profile/{membership_id}"
1851                f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}"
1852            ),
1853            auth=access_token,
1854        )
1855        assert isinstance(resp, dict)
1856        return resp
1857
1858    async def fetch_application_api_usage(
1859        self,
1860        access_token: str,
1861        application_id: int,
1862        /,
1863        *,
1864        start: typing.Optional[datetime.datetime] = None,
1865        end: typing.Optional[datetime.datetime] = None,
1866    ) -> typedefs.JSONObject:
1867
1868        end_date, start_date = time.parse_date_range(end, start)
1869        resp = await self._request(
1870            RequestMethod.GET,
1871            f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}",
1872            auth=access_token,
1873        )
1874        assert isinstance(resp, dict)
1875        return resp
1876
1877    async def fetch_bungie_applications(self) -> typedefs.JSONArray:
1878        resp = await self._request(RequestMethod.GET, "App/FirstParty")
1879        assert isinstance(resp, list)
1880        return resp
1881
1882    async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject:
1883        resp = await self._request(RequestMethod.GET, f"Content/GetContentType/{type}/")
1884        assert isinstance(resp, dict)
1885        return resp
1886
1887    async def fetch_content_by_id(
1888        self, id: int, locale: str, /, *, head: bool = False
1889    ) -> typedefs.JSONObject:
1890        resp = await self._request(
1891            RequestMethod.GET,
1892            f"Content/GetContentById/{id}/{locale}/",
1893            json={"head": head},
1894        )
1895        assert isinstance(resp, dict)
1896        return resp
1897
1898    async def fetch_content_by_tag_and_type(
1899        self, locale: str, tag: str, type: str, *, head: bool = False
1900    ) -> typedefs.JSONObject:
1901        resp = await self._request(
1902            RequestMethod.GET,
1903            f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/",
1904            json={"head": head},
1905        )
1906        assert isinstance(resp, dict)
1907        return resp
1908
1909    async def search_content_with_text(
1910        self,
1911        locale: str,
1912        /,
1913        content_type: str,
1914        search_text: str,
1915        tag: str,
1916        *,
1917        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
1918        source: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1919    ) -> typedefs.JSONObject:
1920
1921        body: typedefs.JSONObject = {}
1922
1923        body["ctype"] = content_type
1924        body["searchtext"] = search_text
1925        body["tag"] = tag
1926
1927        if page is not undefined.UNDEFINED:
1928            body["currentpage"] = page
1929        else:
1930            body["currentpage"] = 1
1931
1932        if source is not undefined.UNDEFINED:
1933            body["source"] = source
1934        else:
1935            source = ""
1936        resp = await self._request(
1937            RequestMethod.GET, f"Content/Search/{locale}/", json=body
1938        )
1939        assert isinstance(resp, dict)
1940        return resp
1941
1942    async def search_content_by_tag_and_type(
1943        self,
1944        locale: str,
1945        tag: str,
1946        type: str,
1947        *,
1948        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
1949    ) -> typedefs.JSONObject:
1950        body: typedefs.JSONObject = {}
1951        body["currentpage"] = 1 if page is undefined.UNDEFINED else page
1952        resp = await self._request(
1953            RequestMethod.GET,
1954            f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/",
1955            json=body,
1956        )
1957        assert isinstance(resp, dict)
1958        return resp
1959
1960    async def search_help_articles(
1961        self, text: str, size: str, /
1962    ) -> typedefs.JSONObject:
1963        resp = await self._request(
1964            RequestMethod.GET, f"Content/SearchHelpArticles/{text}/{size}/"
1965        )
1966        assert isinstance(resp, dict)
1967        return resp
1968
1969    async def fetch_topics_page(
1970        self,
1971        category_filter: int,
1972        group: int,
1973        date_filter: int,
1974        sort: typing.Union[str, bytes],
1975        *,
1976        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
1977        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.UNDEFINED,
1978        tag_filter: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1979    ) -> typedefs.JSONObject:
1980
1981        body: typedefs.JSONObject = {}
1982        if locales is not undefined.UNDEFINED:
1983            body["locales"] = ",".join(str(locales))
1984        else:
1985            body["locales"] = ",".join([])
1986
1987        if tag_filter is not undefined.UNDEFINED:
1988            body["tagstring"] = tag_filter
1989        else:
1990            body["tagstring"] = ""
1991
1992        page = 0 if page is not undefined.UNDEFINED else page
1993
1994        resp = await self._request(
1995            RequestMethod.GET,
1996            f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/",
1997            json=body,
1998        )
1999        assert isinstance(resp, dict)
2000        return resp
2001
2002    async def fetch_core_topics_page(
2003        self,
2004        category_filter: int,
2005        date_filter: int,
2006        sort: typing.Union[str, bytes],
2007        *,
2008        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
2009        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.UNDEFINED,
2010    ) -> typedefs.JSONObject:
2011        body: typedefs.JSONObject = {}
2012
2013        if locales is not undefined.UNDEFINED:
2014            body["locales"] = ",".join(str(locales))
2015        else:
2016            body["locales"] = ",".join([])
2017
2018        resp = await self._request(
2019            RequestMethod.GET,
2020            f"Forum/GetCoreTopicsPaged/{0 if page is undefined.UNDEFINED else page}"
2021            f"/{sort!s}/{date_filter}/{category_filter}/",
2022            json=body,
2023        )
2024        assert isinstance(resp, dict)
2025        return resp
2026
2027    async def fetch_posts_threaded_page(
2028        self,
2029        parent_post: bool,
2030        page: int,
2031        page_size: int,
2032        parent_post_id: int,
2033        reply_size: int,
2034        root_thread_mode: bool,
2035        sort_mode: int,
2036        show_banned: typing.Optional[str] = None,
2037    ) -> typedefs.JSONObject:
2038        resp = await self._request(
2039            RequestMethod.GET,
2040            f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/"
2041            f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/",
2042            json={"showbanned": show_banned},
2043        )
2044        assert isinstance(resp, dict)
2045        return resp
2046
2047    async def fetch_posts_threaded_page_from_child(
2048        self,
2049        child_id: bool,
2050        page: int,
2051        page_size: int,
2052        reply_size: int,
2053        root_thread_mode: bool,
2054        sort_mode: int,
2055        show_banned: typing.Optional[str] = None,
2056    ) -> typedefs.JSONObject:
2057        resp = await self._request(
2058            RequestMethod.GET,
2059            f"Forum/GetPostsThreadedPagedFromChild/{child_id}/"
2060            f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/",
2061            json={"showbanned": show_banned},
2062        )
2063        assert isinstance(resp, dict)
2064        return resp
2065
2066    async def fetch_post_and_parent(
2067        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2068    ) -> typedefs.JSONObject:
2069        resp = await self._request(
2070            RequestMethod.GET,
2071            f"Forum/GetPostAndParent/{child_id}/",
2072            json={"showbanned": show_banned},
2073        )
2074        assert isinstance(resp, dict)
2075        return resp
2076
2077    async def fetch_posts_and_parent_awaiting(
2078        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2079    ) -> typedefs.JSONObject:
2080        resp = await self._request(
2081            RequestMethod.GET,
2082            f"Forum/GetPostAndParentAwaitingApproval/{child_id}/",
2083            json={"showbanned": show_banned},
2084        )
2085        assert isinstance(resp, dict)
2086        return resp
2087
2088    async def fetch_topic_for_content(self, content_id: int, /) -> int:
2089        resp = await self._request(
2090            RequestMethod.GET, f"Forum/GetTopicForContent/{content_id}/"
2091        )
2092        assert isinstance(resp, int)
2093        return resp
2094
2095    async def fetch_forum_tag_suggestions(
2096        self, partial_tag: str, /
2097    ) -> typedefs.JSONObject:
2098        resp = await self._request(
2099            RequestMethod.GET,
2100            "Forum/GetForumTagSuggestions/",
2101            json={"partialtag": partial_tag},
2102        )
2103        assert isinstance(resp, dict)
2104        return resp
2105
2106    async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject:
2107        resp = await self._request(RequestMethod.GET, f"Forum/Poll/{topic_id}/")
2108        assert isinstance(resp, dict)
2109        return resp
2110
2111    async def fetch_recuirement_thread_summaries(self) -> typedefs.JSONArray:
2112        resp = await self._request(RequestMethod.POST, "Forum/Recruit/Summaries/")
2113        assert isinstance(resp, list)
2114        return resp
2115
2116    async def fetch_recommended_groups(
2117        self,
2118        accecss_token: str,
2119        /,
2120        *,
2121        date_range: int = 0,
2122        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
2123    ) -> typedefs.JSONArray:
2124        resp = await self._request(
2125            RequestMethod.POST,
2126            f"GroupV2/Recommended/{int(group_type)}/{date_range}/",
2127            auth=accecss_token,
2128        )
2129        assert isinstance(resp, list)
2130        return resp
2131
2132    async def fetch_available_avatars(self) -> collections.Mapping[str, int]:
2133        resp = await self._request(RequestMethod.GET, "GroupV2/GetAvailableAvatars/")
2134        assert isinstance(resp, dict)
2135        return resp
2136
2137    async def fetch_user_clan_invite_setting(
2138        self,
2139        access_token: str,
2140        /,
2141        membership_type: typedefs.IntAnd[enums.MembershipType],
2142    ) -> bool:
2143        resp = await self._request(
2144            RequestMethod.GET,
2145            f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/",
2146            auth=access_token,
2147        )
2148        assert isinstance(resp, bool)
2149        return resp
2150
2151    async def fetch_banned_group_members(
2152        self, access_token: str, group_id: int, /, *, page: int = 1
2153    ) -> typedefs.JSONObject:
2154        resp = await self._request(
2155            RequestMethod.GET,
2156            f"GroupV2/{group_id}/Banned/?currentpage={page}",
2157            auth=access_token,
2158        )
2159        assert isinstance(resp, dict)
2160        return resp
2161
2162    async def fetch_pending_group_memberships(
2163        self, access_token: str, group_id: int, /, *, current_page: int = 1
2164    ) -> typedefs.JSONObject:
2165        resp = await self._request(
2166            RequestMethod.GET,
2167            f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}",
2168            auth=access_token,
2169        )
2170        assert isinstance(resp, dict)
2171        return resp
2172
2173    async def fetch_invited_group_memberships(
2174        self, access_token: str, group_id: int, /, *, current_page: int = 1
2175    ) -> typedefs.JSONObject:
2176        resp = await self._request(
2177            RequestMethod.GET,
2178            f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}",
2179            auth=access_token,
2180        )
2181        assert isinstance(resp, dict)
2182        return resp
2183
2184    async def invite_member_to_group(
2185        self,
2186        access_token: str,
2187        /,
2188        group_id: int,
2189        membership_id: int,
2190        membership_type: typedefs.IntAnd[enums.MembershipType],
2191        *,
2192        message: undefined.UndefinedOr[str] = undefined.UNDEFINED,
2193    ) -> typedefs.JSONObject:
2194        resp = await self._request(
2195            RequestMethod.POST,
2196            f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/",
2197            auth=access_token,
2198            json={"message": str(message)},
2199        )
2200        assert isinstance(resp, dict)
2201        return resp
2202
2203    async def cancel_group_member_invite(
2204        self,
2205        access_token: str,
2206        /,
2207        group_id: int,
2208        membership_id: int,
2209        membership_type: typedefs.IntAnd[enums.MembershipType],
2210    ) -> typedefs.JSONObject:
2211        resp = await self._request(
2212            RequestMethod.POST,
2213            f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/",
2214            auth=access_token,
2215        )
2216        assert isinstance(resp, dict)
2217        return resp
2218
2219    async def fetch_historical_definition(self) -> typedefs.JSONObject:
2220        resp = await self._request(RequestMethod.GET, "Destiny2/Stats/Definition/")
2221        assert isinstance(resp, dict)
2222        return resp
2223
2224    async def fetch_historical_stats(
2225        self,
2226        character_id: int,
2227        membership_id: int,
2228        membership_type: typedefs.IntAnd[enums.MembershipType],
2229        day_start: datetime.datetime,
2230        day_end: datetime.datetime,
2231        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2232        modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]],
2233        *,
2234        period_type: enums.PeriodType = enums.PeriodType.ALL_TIME,
2235    ) -> typedefs.JSONObject:
2236
2237        end, start = time.parse_date_range(day_end, day_start)
2238        resp = await self._request(
2239            RequestMethod.GET,
2240            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/",
2241            json={
2242                "dayend": end,
2243                "daystart": start,
2244                "groups": [str(int(group)) for group in groups],
2245                "modes": [str(int(mode)) for mode in modes],
2246                "periodType": int(period_type),
2247            },
2248        )
2249        assert isinstance(resp, dict)
2250        return resp
2251
2252    async def fetch_historical_stats_for_account(
2253        self,
2254        membership_id: int,
2255        membership_type: typedefs.IntAnd[enums.MembershipType],
2256        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2257    ) -> typedefs.JSONObject:
2258        resp = await self._request(
2259            RequestMethod.GET,
2260            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/",
2261            json={"groups": [str(int(group)) for group in groups]},
2262        )
2263        assert isinstance(resp, dict)
2264        return resp
2265
2266    async def fetch_aggregated_activity_stats(
2267        self,
2268        character_id: int,
2269        membership_id: int,
2270        membership_type: typedefs.IntAnd[enums.MembershipType],
2271        /,
2272    ) -> typedefs.JSONObject:
2273        resp = await self._request(
2274            RequestMethod.GET,
2275            f"Destiny2/{int(membership_type)}/Account/{membership_id}/"
2276            f"Character/{character_id}/Stats/AggregateActivityStats/",
2277        )
2278        assert isinstance(resp, dict)
2279        return resp

A RESTful client implementation for Bungie's API.

This client is designed to only make HTTP requests and return JSON objects to provide RESTful functionality.

This client is also used within aiobungie.Client which deserialize those returned JSON objects using the factory into Pythonic data classes objects which provide Python functionality.

Example
import aiobungie

async def main():
    async with aiobungie.RESTClient("TOKEN") as rest_client:
        req = await rest_client.fetch_clan_members(4389205)
        clan_members = req['results']
        for member in clan_members:
            for k, v in member['destinyUserInfo'].items():
                print(k, v)
Parameters
  • token (str): A valid application token from Bungie's developer portal.
Other Parameters
  • max_retries (int): The max retries number to retry if the request hit a 5xx status code.
  • client_secret (typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client.
  • client_id (typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
  • enable_debugging (bool | str): Whether to enable logging responses or not.
Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information.
  • "TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
RESTClient( token: str, /, *, client_secret: Optional[str] = None, client_id: Optional[int] = None, client_session: Optional[aiohttp.client.ClientSession] = None, max_retries: int = 4, enable_debugging: Union[Literal['TRACE'], bool, int] = False)
371    def __init__(
372        self,
373        token: str,
374        /,
375        *,
376        client_secret: typing.Optional[str] = None,
377        client_id: typing.Optional[int] = None,
378        client_session: typing.Optional[aiohttp.ClientSession] = None,
379        max_retries: int = 4,
380        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
381    ) -> None:
382        self._session: typing.Optional[aiohttp.ClientSession] = client_session
383        self._lock: typing.Optional[asyncio.Lock] = None
384        self._client_secret = client_secret
385        self._client_id = client_id
386        self._token: str = token
387        self._max_retries = max_retries
388        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
389
390        self._set_debug_level(enable_debugging)
client_id: Optional[int]

Return the client id of this REST client if provided, Otherwise None.

metadata: collections.abc.MutableMapping[typing.Any, typing.Any]

A mutable mapping storage for the user's needs.

This mapping is useful for storing any kind of data that the user may need.

Example
import aiobungie

client = aiobungie.RESTClient(…)

async with client:
    # Fetch auth tokens and store them
    client.metadata["tokens"] = await client.fetch_access_token("code")

# Some other time.
async with client:
    # Retrieve the tokens
    tokens: aiobungie.OAuth2Response = client.metadata["tokens"]

    # Use them to fetch your user.
    user = await client.fetch_current_user_memberships(tokens.access_token)
is_alive: bool

Returns True if the REST client is alive and False otherwise.

@typing.final
async def close(self) -> None:
404    @typing.final
405    async def close(self) -> None:
406        if self._session is None:
407            raise RuntimeError("REST client is not running.")
408
409        await self._session.close()
410        self._session = None

Close this REST client session if it was acquired.

This method is automatically called when using async with contextmanager.

Raises
  • RuntimeError: If the client is already closed.
@typing.final
def open(self) -> None:
412    @typing.final
413    def open(self) -> None:
414        """Open a new client session. This is called internally with contextmanager usage."""
415        if self._session:
416            raise RuntimeError("Cannot open REST client when it's already open.")
417
418        self._session = aiohttp.ClientSession(
419            connector=aiohttp.TCPConnector(ssl=False),
420            raise_for_status=False,
421            timeout=aiohttp.ClientTimeout(total=30.0),
422        )

Open a new client session. This is called internally with contextmanager usage.

@typing.final
def enable_debugging( self, level: Union[Literal['TRACE'], bool, int] = False, file: Union[pathlib.Path, str, NoneType] = None, /) -> None:
424    @typing.final
425    def enable_debugging(
426        self,
427        level: typing.Union[typing.Literal["TRACE"], bool, int] = False,
428        file: typing.Optional[typing.Union[pathlib.Path, str]] = None,
429        /,
430    ) -> None:
431        self._set_debug_level(level, file)

Enables debugging for the REST calls.

Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information.
  • "TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
Parameters
  • level (str | bool | int): The level of debugging to enable.
  • file (pathlib.Path | str | None): The file path to write the debug logs to. If provided.
@typing.final
async def static_request( self, method: Union[aiobungie.RequestMethod, str], path: str, *, auth: Optional[str] = None, json: Optional[dict[str, Any]] = None) -> Union[dict[str, Any], list[Any], bytes, int, bool, NoneType]:
433    @typing.final
434    async def static_request(
435        self,
436        method: typing.Union[RequestMethod, str],
437        path: str,
438        *,
439        auth: typing.Optional[str] = None,
440        json: typing.Optional[dict[str, typing.Any]] = None,
441    ) -> ResponseSig:
442        return await self._request(method, path, auth=auth, json=json)

Perform an HTTP request given a valid Bungie endpoint.

Parameters
  • method (aiobungie.RequestMethod | str): The request method, This may be GET, POST, PUT, etc.
  • path (str): The Bungie endpoint or path. A path must look something like this Destiny2/3/Profile/46111239123/...
  • auth (str | None): An optional bearer token for methods that requires OAuth2 Authorization header.
  • json (dict[str, typing.Any] | None): An optional JSON data to include in the request.
Returns
  • aiobungie.rest.ResponseSig: The response payload.
@typing.final
def build_oauth2_url( self, client_id: Optional[int] = None) -> Optional[aiobungie.builders.OAuthURL]:
444    @typing.final
445    def build_oauth2_url(
446        self, client_id: typing.Optional[int] = None
447    ) -> typing.Optional[builders.OAuthURL]:
448        client_id = client_id or self._client_id
449        if client_id is None:
450            return None
451
452        return builders.OAuthURL(client_id=client_id)

Builds an OAuth2 URL using the provided user REST/Base client secret/id.

You can't get the complete string URL by using .compile() method.

Parameters
  • client_id (int | None): An optional client id to provide, If left None it will roll back to the id passed to the RESTClient, If both is None this method will return None.
Returns
async def fetch_oauth2_tokens(self, code: str, /) -> aiobungie.builders.OAuth2Response:
663    async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response:
664        if not isinstance(self._client_secret, (str, int)):
665            raise TypeError(
666                "Expected (str, int) for client secret "
667                f"but got {type(self._client_secret).__name__}"  # type: ignore
668            )
669
670        headers = {
671            "client_secret": self._client_secret,
672        }
673
674        data = (
675            f"grant_type=authorization_code&code={code}"
676            f"&client_id={self._client_id}&client_secret={self._client_secret}"
677        )
678
679        response = await self._request(
680            RequestMethod.POST, "", headers=headers, data=data, oauth2=True
681        )
682        assert isinstance(response, dict)
683        return builders.OAuth2Response.build_response(response)

Makes a POST request and fetch the OAuth2 access_token and refresh token.

Parameters
  • code (str): The Authorization code received from the authorization endpoint found in the URL parameters.
Returns
Raises
async def refresh_access_token(self, refresh_token: str, /) -> aiobungie.builders.OAuth2Response:
685    async def refresh_access_token(
686        self, refresh_token: str, /
687    ) -> builders.OAuth2Response:
688        if not isinstance(self._client_secret, (int, str)):
689            raise TypeError(
690                f"Expected (str, int) for client secret but got {type(self._client_secret).__name__}"  # type: ignore
691            )
692
693        data = {
694            "grant_type": "refresh_token",
695            "refresh_token": refresh_token,
696            "client_id": self._client_id,
697            "client_secret": self._client_secret,
698            "Content-Type": "application/x-www-form-urlencoded",
699        }
700
701        response = await self._request(RequestMethod.POST, "", data=data, oauth2=True)
702        assert isinstance(response, dict)
703        return builders.OAuth2Response.build_response(response)

Refresh OAuth2 access token given its refresh token.

Parameters
  • refresh_token (str): The refresh token.
Returns
async def fetch_bungie_user(self, id: int) -> dict[str, typing.Any]:
705    async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject:
706        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
707        resp = await self._request(
708            RequestMethod.GET, f"User/GetBungieNetUserById/{id}/"
709        )
710        assert isinstance(resp, dict)
711        return resp

Fetch a Bungie user by their id.

Parameters
  • id (int): The user id.
Returns
Raises
async def fetch_user_themes(self) -> list[typing.Any]:
713    async def fetch_user_themes(self) -> typedefs.JSONArray:
714        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
715        resp = await self._request(RequestMethod.GET, "User/GetAvailableThemes/")
716        assert isinstance(resp, list)
717        return resp

Fetch all available user themes.

Returns
async def fetch_membership_from_id( self, id: int, type: Union[int, aiobungie.MembershipType] = <MembershipType.NONE: 0>, /) -> dict[str, typing.Any]:
719    async def fetch_membership_from_id(
720        self,
721        id: int,
722        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
723        /,
724    ) -> typedefs.JSONObject:
725        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
726        resp = await self._request(
727            RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}"
728        )
729        assert isinstance(resp, dict)
730        return resp

Fetch Bungie user's memberships from their id.

Parameters
Returns
Raises
async def fetch_player( self, name: str, code: int, type: Union[int, aiobungie.MembershipType] = <MembershipType.ALL: -1>, /) -> list[typing.Any]:
732    async def fetch_player(
733        self,
734        name: str,
735        code: int,
736        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
737        /,
738    ) -> typedefs.JSONArray:
739        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
740        resp = await self._request(
741            RequestMethod.POST,
742            f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}",
743            json={"displayName": name, "displayNameCode": code},
744        )
745        assert isinstance(resp, list)
746        return resp

Fetch a Destiny 2 Player.

Parameters
Returns
Raises
async def search_users(self, name: str, /) -> dict[str, typing.Any]:
748    async def search_users(self, name: str, /) -> typedefs.JSONObject:
749        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
750        resp = await self._request(
751            RequestMethod.POST,
752            "User/Search/GlobalName/0",
753            json={"displayNamePrefix": name},
754        )
755        assert isinstance(resp, dict)
756        return resp

Search for users by their global name and return all users who share this name.

Parameters
  • name (str): The user name.
Returns
Raises
async def fetch_clan_from_id( self, id: int, /, access_token: Optional[str] = None) -> dict[str, typing.Any]:
758    async def fetch_clan_from_id(
759        self, id: int, /, access_token: typing.Optional[str] = None
760    ) -> typedefs.JSONObject:
761        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
762        resp = await self._request(
763            RequestMethod.GET, f"GroupV2/{id}", auth=access_token
764        )
765        assert isinstance(resp, dict)
766        return resp

Fetch a Bungie Clan by its id.

Parameters
  • id (int): The clan id.
Other Parameters
  • access_token (typing.Optional[str]): An optional access token to make the request with.

    If the token was bound to a member of the clan, This field aiobungie.crates.Clan.current_user_membership will be available and will return the membership of the user who made this request.

Returns
Raises
async def fetch_clan( self, name: str, /, access_token: Optional[str] = None, *, type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> dict[str, typing.Any]:
768    async def fetch_clan(
769        self,
770        name: str,
771        /,
772        access_token: typing.Optional[str] = None,
773        *,
774        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
775    ) -> typedefs.JSONObject:
776        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
777        resp = await self._request(
778            RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token
779        )
780        assert isinstance(resp, dict)
781        return resp

Fetch a Clan by its name. This method will return the first clan found with given name name.

Parameters
  • name (str): The clan name.
Other Parameters
Returns
Raises
async def fetch_clan_admins(self, clan_id: int, /) -> dict[str, typing.Any]:
783    async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject:
784        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
785        resp = await self._request(
786            RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/"
787        )
788        assert isinstance(resp, dict)
789        return resp

Fetch the admins and founder members of the clan.

Parameters
  • clan_id (int): The clan id.
Returns
Raises
async def fetch_clan_conversations(self, clan_id: int, /) -> list[typing.Any]:
791    async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray:
792        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
793        resp = await self._request(
794            RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/"
795        )
796        assert isinstance(resp, list)
797        return resp

Fetch a clan's conversations.

Parameters
  • clan_id (int): The clan's id.
Returns
async def fetch_application(self, appid: int, /) -> dict[str, typing.Any]:
799    async def fetch_application(self, appid: int, /) -> typedefs.JSONObject:
800        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
801        resp = await self._request(RequestMethod.GET, f"App/Application/{appid}")
802        assert isinstance(resp, dict)
803        return resp

Fetch a Bungie Application.

Parameters
  • appid (int): The application id.
Returns
async def fetch_character( self, member_id: int, membership_type: Union[int, aiobungie.MembershipType], character_id: int, components: list[aiobungie.ComponentType], auth: Optional[str] = None) -> dict[str, typing.Any]:
805    async def fetch_character(
806        self,
807        member_id: int,
808        membership_type: typedefs.IntAnd[enums.MembershipType],
809        character_id: int,
810        components: list[enums.ComponentType],
811        auth: typing.Optional[str] = None,
812    ) -> typedefs.JSONObject:
813        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
814        collector = _collect_components(components)
815        response = await self._request(
816            RequestMethod.GET,
817            f"Destiny2/{int(membership_type)}/Profile/{member_id}/"
818            f"Character/{character_id}/?components={collector}",
819            auth=auth,
820        )
821        assert isinstance(response, dict)
822        return response

Fetch a Destiny 2 player's characters.

Parameters
Other Parameters
  • auth (typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
Raises
async def fetch_activities( self, member_id: int, character_id: int, mode: Union[int, aiobungie.GameMode], membership_type: Union[int, aiobungie.MembershipType] = <MembershipType.ALL: -1>, *, page: int = 0, limit: int = 1) -> dict[str, typing.Any]:
824    async def fetch_activities(
825        self,
826        member_id: int,
827        character_id: int,
828        mode: typedefs.IntAnd[enums.GameMode],
829        membership_type: typedefs.IntAnd[
830            enums.MembershipType
831        ] = enums.MembershipType.ALL,
832        *,
833        page: int = 0,
834        limit: int = 1,
835    ) -> typedefs.JSONObject:
836        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
837        resp = await self._request(
838            RequestMethod.GET,
839            f"Destiny2/{int(membership_type)}/Account/"
840            f"{member_id}/Character/{character_id}/Stats/Activities"
841            f"/?mode={int(mode)}&count={limit}&page={page}",
842        )
843        assert isinstance(resp, dict)
844        return resp

Fetch a Destiny 2 activity for the specified user id and character.

Parameters
  • member_id (int): The user id that starts with 4611.
  • character_id (int): The id of the character to retrieve.
  • mode (aiobungie.typedefs.IntAnd[aiobungie.GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
Returns
Raises
async def fetch_vendor_sales(self) -> dict[str, typing.Any]:
846    async def fetch_vendor_sales(self) -> typedefs.JSONObject:
847        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
848        resp = await self._request(
849            RequestMethod.GET,
850            f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}",
851        )
852        assert isinstance(resp, dict)
853        return resp
async def fetch_profile( self, membership_id: int, type: Union[int, aiobungie.MembershipType], components: list[aiobungie.ComponentType], auth: Optional[str] = None) -> dict[str, typing.Any]:
855    async def fetch_profile(
856        self,
857        membership_id: int,
858        type: typedefs.IntAnd[enums.MembershipType],
859        components: list[enums.ComponentType],
860        auth: typing.Optional[str] = None,
861    ) -> typedefs.JSONObject:
862        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
863        collector = _collect_components(components)
864        response = await self._request(
865            RequestMethod.GET,
866            f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}",
867            auth=auth,
868        )
869        assert isinstance(response, dict)
870        return response

Fetch a bungie profile.

Parameters
Other Parameters
  • auth (typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
Raises
async def fetch_entity(self, type: str, hash: int) -> dict[str, typing.Any]:
872    async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject:
873        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
874        response = await self._request(
875            RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}"
876        )
877        assert isinstance(response, dict)
878        return response

Fetch a Destiny definition item given its type and hash.

Parameters
  • type (str): Entity's type definition.
  • hash (int): Entity's hash.
Returns
async def fetch_inventory_item(self, hash: int, /) -> dict[str, typing.Any]:
880    async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject:
881        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
882        resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash)
883        assert isinstance(resp, dict)
884        return resp

Fetch a Destiny inventory item entity given a its hash.

Parameters
  • hash (int): Entity's hash.
Returns
async def fetch_objective_entity(self, hash: int, /) -> dict[str, typing.Any]:
886    async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject:
887        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
888        resp = await self.fetch_entity("DestinyObjectiveDefinition", hash)
889        assert isinstance(resp, dict)
890        return resp

Fetch a Destiny objective entity given a its hash.

Parameters
  • hash (int): objective's hash.
Returns
async def fetch_groups_for_member( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, filter: int = 0, group_type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> dict[str, typing.Any]:
892    async def fetch_groups_for_member(
893        self,
894        member_id: int,
895        member_type: typedefs.IntAnd[enums.MembershipType],
896        /,
897        *,
898        filter: int = 0,
899        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
900    ) -> typedefs.JSONObject:
901        resp = await self._request(
902            RequestMethod.GET,
903            f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
904        )
905        assert isinstance(resp, dict)
906        return resp

Fetch the information about the groups for a member.

Parameters
Other Parameters
Returns
async def fetch_potential_groups_for_member( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, filter: int = 0, group_type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> dict[str, typing.Any]:
908    async def fetch_potential_groups_for_member(
909        self,
910        member_id: int,
911        member_type: typedefs.IntAnd[enums.MembershipType],
912        /,
913        *,
914        filter: int = 0,
915        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
916    ) -> typedefs.JSONObject:
917        resp = await self._request(
918            RequestMethod.GET,
919            f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
920        )
921        assert isinstance(resp, dict)
922        return resp

Get information about the groups that a given member has applied to or been invited to.

Parameters
Other Parameters
Returns
async def fetch_clan_members( self, clan_id: int, /, *, name: Optional[str] = None, type: Union[int, aiobungie.MembershipType] = <MembershipType.NONE: 0>) -> dict[str, typing.Any]:
924    async def fetch_clan_members(
925        self,
926        clan_id: int,
927        /,
928        *,
929        name: typing.Optional[str] = None,
930        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
931    ) -> typedefs.JSONObject:
932        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
933        resp = await self._request(
934            RequestMethod.GET,
935            f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}&currentpage=1",
936        )
937        assert isinstance(resp, dict)
938        return resp

Fetch all Bungie Clan members.

Parameters
  • clan_id (builsins.int): The clans id
Other Parameters
Returns
Raises
async def fetch_hardlinked_credentials( self, credential: int, type: Union[int, aiobungie.CredentialType] = <CredentialType.STEAMID: 12>, /) -> dict[str, typing.Any]:
940    async def fetch_hardlinked_credentials(
941        self,
942        credential: int,
943        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
944        /,
945    ) -> typedefs.JSONObject:
946        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
947        resp = await self._request(
948            RequestMethod.GET,
949            f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/",
950        )
951        assert isinstance(resp, dict)
952        return resp

Gets any hard linked membership given a credential.

Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now. Cross Save aware.

Parameters
Returns
async def fetch_user_credentials(self, access_token: str, membership_id: int, /) -> list[typing.Any]:
954    async def fetch_user_credentials(
955        self, access_token: str, membership_id: int, /
956    ) -> typedefs.JSONArray:
957        resp = await self._request(
958            RequestMethod.GET,
959            f"User/GetCredentialTypesForTargetAccount/{membership_id}",
960            auth=access_token,
961        )
962        assert isinstance(resp, list)
963        return resp

Fetch an array of credential types attached to the requested account.

This method require OAuth2 Bearer access token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • membership_id (int): The id of the membership to return.
Returns
Raises
async def insert_socket_plug( self, action_token: str, /, instance_id: int, plug: Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]], character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
965    async def insert_socket_plug(
966        self,
967        action_token: str,
968        /,
969        instance_id: int,
970        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
971        character_id: int,
972        membership_type: typedefs.IntAnd[enums.MembershipType],
973    ) -> typedefs.JSONObject:
974
975        if isinstance(plug, builders.PlugSocketBuilder):
976            plug = plug.collect()
977
978        body = {
979            "actionToken": action_token,
980            "itemInstanceId": instance_id,
981            "plug": plug,
982            "characterId": character_id,
983            "membershipType": int(membership_type),
984        }
985        resp = await self._request(
986            RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body
987        )
988        assert isinstance(resp, dict)
989        return resp

Insert a plug into a socketed item.

OAuth2: AdvancedWriteActions scope is required

Parameters
  • action_token (str): Action token provided by the AwaGetActionToken API call.
  • instance_id (int): The item instance id that's plug inserted.
  • plug (typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
    aiobungie.PlugSocketBuilder()
    .set_socket_array(0)
    .set_socket_index(0)
    .set_plug_item(3023847)
    .collect()
)
await insert_socket_plug_free(..., plug=plug)

character_id : int The character's id. membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType] The membership type.

Returns
Raises
async def insert_socket_plug_free( self, access_token: str, /, instance_id: int, plug: Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]], character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
 991    async def insert_socket_plug_free(
 992        self,
 993        access_token: str,
 994        /,
 995        instance_id: int,
 996        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
 997        character_id: int,
 998        membership_type: typedefs.IntAnd[enums.MembershipType],
 999    ) -> typedefs.JSONObject:
1000
1001        if isinstance(plug, builders.PlugSocketBuilder):
1002            plug = plug.collect()
1003
1004        body = {
1005            "itemInstanceId": instance_id,
1006            "plug": plug,
1007            "characterId": character_id,
1008            "membershipType": int(membership_type),
1009        }
1010        resp = await self._request(
1011            RequestMethod.POST,
1012            "Destiny2/Actions/Items/InsertSocketPlugFree",
1013            json=body,
1014            auth=access_token,
1015        )
1016        assert isinstance(resp, dict)
1017        return resp

Insert a plug into a socketed item. This doesn't require an Action token.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • instance_id (int): The item instance id that's plug inserted.
  • plug (typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
    aiobungie.PlugSocketBuilder()
    .set_socket_array(0)
    .set_socket_index(0)
    .set_plug_item(3023847)
    .collect()
)
await insert_socket_plug_free(..., plug=plug)

character_id : int The character's id. membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType] The membership type.

Returns
Raises
async def set_item_lock_state( self, access_token: str, state: bool, /, item_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> int:
1019    async def set_item_lock_state(
1020        self,
1021        access_token: str,
1022        state: bool,
1023        /,
1024        item_id: int,
1025        character_id: int,
1026        membership_type: typedefs.IntAnd[enums.MembershipType],
1027    ) -> int:
1028        body = {
1029            "state": state,
1030            "itemId": item_id,
1031            "characterId": character_id,
1032            "membership_type": int(membership_type),
1033        }
1034        response = await self._request(
1035            RequestMethod.POST,
1036            "Destiny2/Actions/Items/SetLockState",
1037            json=body,
1038            auth=access_token,
1039        )
1040        assert isinstance(response, int)
1041        return response

Set the Lock State for an instanced item.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • state (bool): If True, The item will be locked, If False, The item will be unlocked.
  • item_id (int): The item id.
  • character_id (int): The character id.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
  • int: An integer represents whether the request was successful or failed.
Raises
async def set_quest_track_state( self, access_token: str, state: bool, /, item_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> int:
1043    async def set_quest_track_state(
1044        self,
1045        access_token: str,
1046        state: bool,
1047        /,
1048        item_id: int,
1049        character_id: int,
1050        membership_type: typedefs.IntAnd[enums.MembershipType],
1051    ) -> int:
1052        body = {
1053            "state": state,
1054            "itemId": item_id,
1055            "characterId": character_id,
1056            "membership_type": int(membership_type),
1057        }
1058        response = await self._request(
1059            RequestMethod.POST,
1060            "Destiny2/Actions/Items/SetTrackedState",
1061            json=body,
1062            auth=access_token,
1063        )
1064        assert isinstance(response, int)
1065        return response

Set the Tracking State for an instanced Quest or Bounty.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • state (bool): If True, The item will be locked, If False, The item will be unlocked.
  • item_id (int): The item id.
  • character_id (int): The character id.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
  • int: An integer represents whether the request was successful or failed.
Raises
async def fetch_manifest_path(self) -> dict[str, typing.Any]:
1067    async def fetch_manifest_path(self) -> typedefs.JSONObject:
1068        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1069        path = await self._request(RequestMethod.GET, "Destiny2/Manifest")
1070        assert isinstance(path, dict)
1071        return path

Fetch the manifest JSON paths.

Returns
  • typedefs.JSONObject: The manifest JSON paths.
async def read_manifest_bytes(self, language: str = 'en', /) -> bytes:
1073    async def read_manifest_bytes(self, language: str = "en", /) -> bytes:
1074        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1075        _ensure_manifest_language(language)
1076
1077        content = await self.fetch_manifest_path()
1078        resp = await self._request(
1079            RequestMethod.GET,
1080            content["mobileWorldContentPaths"][language],
1081            unwrapping="read",
1082            base=True,
1083        )
1084        assert isinstance(resp, bytes)
1085        return resp

Read raw manifest SQLite database bytes response.

This method can be used to write the bytes to zipped file and then extract it to get the manifest content.

Parameters
  • language (str): The manifest database language bytes to get.
Returns
  • bytes: The bytes to read and write the manifest database.
async def download_manifest( self, language: str = 'en', name: str = 'manifest', path: Union[pathlib.Path, str] = '.', *, force: bool = False) -> None:
1087    async def download_manifest(
1088        self,
1089        language: str = "en",
1090        name: str = "manifest",
1091        path: typing.Union[pathlib.Path, str] = ".",
1092        *,
1093        force: bool = False,
1094    ) -> None:
1095        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1096        complete_path = _get_path(name, path, sql=True)
1097
1098        if complete_path.exists() and force:
1099            if force:
1100                _LOG.info(
1101                    f"Found manifest in {complete_path!s}. Forcing to Re-Download."
1102                )
1103                complete_path.unlink(missing_ok=True)
1104
1105                return await self.download_manifest(language, name, path, force=force)
1106
1107            else:
1108                raise FileExistsError(
1109                    "Manifest file already exists, "
1110                    "To force download, set the `force` parameter to `True`."
1111                )
1112
1113        _LOG.info(f"Downloading manifest. Location: {complete_path!s}")
1114        data_bytes = await self.read_manifest_bytes(language)
1115        await asyncio.get_running_loop().run_in_executor(
1116            None, _write_sqlite_bytes, data_bytes, path, name
1117        )

A helper method to download the manifest.

Note

This method downloads the sqlite database and not JSON. Use RESTInterface.download_json_manifest for the JSON version.

Parameters
  • language (str): The manifest language to download, Default is english.
  • path (str | pathlib.Path): The path to save the manifest sqlite database. Example "D:/", Default is the current directory.
  • name (str): The manifest database file name. Default is manifest
  • force (bool): Whether to force the download. Default is False. However if set to true the old file will get removed and a new one will being to download.
Returns
  • None
Raises
  • FileNotFoundError: If the manifest file exists and force is False.
  • ValueError: If the provided language was not recognized.
async def download_json_manifest( self, file_name: str = 'manifest', path: Union[str, pathlib.Path] = '.', language: str = 'en') -> None:
1119    async def download_json_manifest(
1120        self,
1121        file_name: str = "manifest",
1122        path: typing.Union[str, pathlib.Path] = ".",
1123        language: str = "en",
1124    ) -> None:
1125        _ensure_manifest_language(language)
1126
1127        _LOG.info(f"Downloading manifest JSON to {_get_path(file_name, path)!r}...")
1128
1129        content = await self.fetch_manifest_path()
1130        json_bytes = await self._request(
1131            RequestMethod.GET,
1132            content["jsonWorldContentPaths"][language],
1133            unwrapping="read",
1134            base=True,
1135        )
1136
1137        await asyncio.get_running_loop().run_in_executor(
1138            None, _write_json_bytes, json_bytes, file_name, path
1139        )
1140        _LOG.info("Finished downloading manifest JSON.")

Download the Bungie manifest json file.

Parameters
  • file_name (str): The file name to save the manifest json file. Default is manifest.
  • path (str | pathlib.Path): The path to save the manifest json file. Default is the current directory. Example "D:/"
  • language (str): The manifest database language bytes to get. Default is English.
async def fetch_manifest_version(self) -> str:
1142    async def fetch_manifest_version(self) -> str:
1143        return typing.cast(str, (await self.fetch_manifest_path())["version"])

Fetch the manifest version.

Returns
  • str: The manifest version.
async def fetch_linked_profiles( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, all: bool = False) -> dict[str, typing.Any]:
1145    async def fetch_linked_profiles(
1146        self,
1147        member_id: int,
1148        member_type: typedefs.IntAnd[enums.MembershipType],
1149        /,
1150        *,
1151        all: bool = False,
1152    ) -> typedefs.JSONObject:
1153        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1154        resp = await self._request(
1155            RequestMethod.GET,
1156            f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}",
1157        )
1158        assert isinstance(resp, dict)
1159        return resp

Returns a summary information about all profiles linked to the requested member.

The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.

It will only return linked accounts whose linkages you are allowed to view.

Parameters
Other Parameters
  • all (bool): If provided and set to True, All memberships regardless of whether thry're obscured by overrides will be returned,

    If provided and set to False, Only available memberships will be returned. The default for this is False.

Returns
async def fetch_clan_banners(self) -> dict[str, typing.Any]:
1161    async def fetch_clan_banners(self) -> typedefs.JSONObject:
1162        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1163        resp = await self._request(
1164            RequestMethod.GET, "Destiny2/Clan/ClanBannerDictionary/"
1165        )
1166        assert isinstance(resp, dict)
1167        return resp

Fetch the values of the clan banners.

Returns
async def fetch_public_milestones(self) -> dict[str, typing.Any]:
1169    async def fetch_public_milestones(self) -> typedefs.JSONObject:
1170        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1171        resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/")
1172        assert isinstance(resp, dict)
1173        return resp

Fetch the available milestones.

Returns
async def fetch_public_milestone_content(self, milestone_hash: int, /) -> dict[str, typing.Any]:
1175    async def fetch_public_milestone_content(
1176        self, milestone_hash: int, /
1177    ) -> typedefs.JSONObject:
1178        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1179        resp = await self._request(
1180            RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/"
1181        )
1182        assert isinstance(resp, dict)
1183        return resp

Fetch the milestone content given its hash.

Parameters
  • milestone_hash (int): The milestone hash.
Returns
async def fetch_current_user_memberships(self, access_token: str, /) -> dict[str, typing.Any]:
1185    async def fetch_current_user_memberships(
1186        self, access_token: str, /
1187    ) -> typedefs.JSONObject:
1188        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1189        resp = await self._request(
1190            RequestMethod.GET,
1191            "User/GetMembershipsForCurrentUser/",
1192            auth=access_token,
1193        )
1194        assert isinstance(resp, dict)
1195        return resp

Fetch a bungie user's accounts with the signed in user. This GET method requires a Bearer access token for the authorization.

This requires OAuth2 scope enabled and the valid Bearer access_token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def equip_item( self, access_token: str, /, item_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> None:
1197    async def equip_item(
1198        self,
1199        access_token: str,
1200        /,
1201        item_id: int,
1202        character_id: int,
1203        membership_type: typedefs.IntAnd[enums.MembershipType],
1204    ) -> None:
1205        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1206        payload = {
1207            "itemId": item_id,
1208            "characterId": character_id,
1209            "membershipType": int(membership_type),
1210        }
1211
1212        await self._request(
1213            RequestMethod.POST,
1214            "Destiny2/Actions/Items/EquipItem/",
1215            json=payload,
1216            auth=access_token,
1217        )

Equip an item to a character.

This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item id.
  • character_id (int): The character's id to equip the item to.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type assocaiated with this player.
async def equip_items( self, access_token: str, /, item_ids: list[int], character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> None:
1219    async def equip_items(
1220        self,
1221        access_token: str,
1222        /,
1223        item_ids: list[int],
1224        character_id: int,
1225        membership_type: typedefs.IntAnd[enums.MembershipType],
1226    ) -> None:
1227        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1228        payload = {
1229            "itemIds": item_ids,
1230            "characterId": character_id,
1231            "membershipType": int(membership_type),
1232        }
1233        await self._request(
1234            RequestMethod.POST,
1235            "Destiny2/Actions/Items/EquipItems/",
1236            json=payload,
1237            auth=access_token,
1238        )

Equip multiple items to a character.

This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_ids (list[int]): A list of item ids.
  • character_id (int): The character's id to equip the item to.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type assocaiated with this player.
async def ban_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], *, length: int = 0, comment: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> None:
1240    async def ban_clan_member(
1241        self,
1242        access_token: str,
1243        /,
1244        group_id: int,
1245        membership_id: int,
1246        membership_type: typedefs.IntAnd[enums.MembershipType],
1247        *,
1248        length: int = 0,
1249        comment: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1250    ) -> None:
1251        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1252        payload = {"comment": str(comment), "length": length}
1253        await self._request(
1254            RequestMethod.POST,
1255            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/",
1256            json=payload,
1257            auth=access_token,
1258        )

Bans a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to ban.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
async def unban_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> None:
1260    async def unban_clan_member(
1261        self,
1262        access_token: str,
1263        /,
1264        group_id: int,
1265        membership_id: int,
1266        membership_type: typedefs.IntAnd[enums.MembershipType],
1267    ) -> None:
1268        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1269        await self._request(
1270            RequestMethod.POST,
1271            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/",
1272            auth=access_token,
1273        )

Unbans a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to unban.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
async def kick_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
1275    async def kick_clan_member(
1276        self,
1277        access_token: str,
1278        /,
1279        group_id: int,
1280        membership_id: int,
1281        membership_type: typedefs.IntAnd[enums.MembershipType],
1282    ) -> typedefs.JSONObject:
1283        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1284        resp = await self._request(
1285            RequestMethod.POST,
1286            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/",
1287            auth=access_token,
1288        )
1289        assert isinstance(resp, dict)
1290        return resp

Kick a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to kick.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
async def edit_clan( self, access_token: str, /, group_id: int, *, name: Optional[str] = None, about: Optional[str] = None, motto: Optional[str] = None, theme: Optional[str] = None, tags: Optional[collections.abc.Sequence[str]] = None, is_public: Optional[bool] = None, locale: Optional[str] = None, avatar_image_index: Optional[int] = None, membership_option: Union[NoneType, int, aiobungie.MembershipOption] = None, allow_chat: Optional[bool] = None, chat_security: Optional[Literal[0, 1]] = None, call_sign: Optional[str] = None, homepage: Optional[Literal[0, 1, 2]] = None, enable_invite_messaging_for_admins: Optional[bool] = None, default_publicity: Optional[Literal[0, 1, 2]] = None, is_public_topic_admin: Optional[bool] = None) -> None:
1292    async def edit_clan(
1293        self,
1294        access_token: str,
1295        /,
1296        group_id: int,
1297        *,
1298        name: typedefs.NoneOr[str] = None,
1299        about: typedefs.NoneOr[str] = None,
1300        motto: typedefs.NoneOr[str] = None,
1301        theme: typedefs.NoneOr[str] = None,
1302        tags: typedefs.NoneOr[collections.Sequence[str]] = None,
1303        is_public: typedefs.NoneOr[bool] = None,
1304        locale: typedefs.NoneOr[str] = None,
1305        avatar_image_index: typedefs.NoneOr[int] = None,
1306        membership_option: typedefs.NoneOr[
1307            typedefs.IntAnd[enums.MembershipOption]
1308        ] = None,
1309        allow_chat: typedefs.NoneOr[bool] = None,
1310        chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None,
1311        call_sign: typedefs.NoneOr[str] = None,
1312        homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1313        enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None,
1314        default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1315        is_public_topic_admin: typedefs.NoneOr[bool] = None,
1316    ) -> None:
1317        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1318        payload = {
1319            "name": name,
1320            "about": about,
1321            "motto": motto,
1322            "theme": theme,
1323            "tags": tags,
1324            "isPublic": is_public,
1325            "avatarImageIndex": avatar_image_index,
1326            "isPublicTopicAdminOnly": is_public_topic_admin,
1327            "allowChat": allow_chat,
1328            "chatSecurity": chat_security,
1329            "callsign": call_sign,
1330            "homepage": homepage,
1331            "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins,
1332            "defaultPublicity": default_publicity,
1333            "locale": locale,
1334        }
1335        if membership_option is not None:
1336            payload["membershipOption"] = int(membership_option)
1337
1338        await self._request(
1339            RequestMethod.POST,
1340            f"GroupV2/{group_id}/Edit",
1341            json=payload,
1342            auth=access_token,
1343        )

Edit a clan.

Notes
  • This request requires OAuth2: oauth2: AdminGroups scope.
  • All arguments will default to None if not provided. This does not include access_token and group_id
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id to edit.
Other Parameters
async def edit_clan_options( self, access_token: str, /, group_id: int, *, invite_permissions_override: Optional[bool] = None, update_culture_permissionOverride: Optional[bool] = None, host_guided_game_permission_override: Optional[Literal[0, 1, 2]] = None, update_banner_permission_override: Optional[bool] = None, join_level: Union[NoneType, int, aiobungie.ClanMemberType] = None) -> None:
1345    async def edit_clan_options(
1346        self,
1347        access_token: str,
1348        /,
1349        group_id: int,
1350        *,
1351        invite_permissions_override: typedefs.NoneOr[bool] = None,
1352        update_culture_permissionOverride: typedefs.NoneOr[bool] = None,
1353        host_guided_game_permission_override: typedefs.NoneOr[
1354            typing.Literal[0, 1, 2]
1355        ] = None,
1356        update_banner_permission_override: typedefs.NoneOr[bool] = None,
1357        join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None,
1358    ) -> None:
1359
1360        payload = {
1361            "InvitePermissionOverride": invite_permissions_override,
1362            "UpdateCulturePermissionOverride": update_culture_permissionOverride,
1363            "HostGuidedGamePermissionOverride": host_guided_game_permission_override,
1364            "UpdateBannerPermissionOverride": update_banner_permission_override,
1365            "JoinLevel": int(join_level) if join_level else None,
1366        }
1367
1368        await self._request(
1369            RequestMethod.POST,
1370            f"GroupV2/{group_id}/EditFounderOptions",
1371            json=payload,
1372            auth=access_token,
1373        )

Edit the clan options.

Notes
  • This request requires OAuth2: oauth2: AdminGroups scope.
  • All arguments will default to None if not provided. This does not include access_token and group_id
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
Other Parameters
  • invite_permissions_override (aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to invite new members to group Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • update_culture_permissionOverride (aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update group culture Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • host_guided_game_permission_override (aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): Minimum Member Level allowed to host guided games Always Allowed: Founder, Acting Founder, Admin Allowed Overrides: 0 -> None, 1 -> Beginner 2 -> Member. Default is Member for clans, None for groups, although this means nothing for groups.
  • update_banner_permission_override (aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update banner Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • join_level (aiobungie.ClanMemberType): Level to join a member at when accepting an invite, application, or joining an open clan. Default is aiobungie.ClanMemberType.BEGINNER
async def fetch_friends(self, access_token: str, /) -> dict[str, typing.Any]:
1375    async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject:
1376        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1377        resp = await self._request(
1378            RequestMethod.GET,
1379            "Social/Friends/",
1380            auth=access_token,
1381        )
1382        assert isinstance(resp, dict)
1383        return resp

Fetch bungie friend list.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_friend_requests(self, access_token: str, /) -> dict[str, typing.Any]:
1385    async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject:
1386        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1387        resp = await self._request(
1388            RequestMethod.GET,
1389            "Social/Friends/Requests",
1390            auth=access_token,
1391        )
1392        assert isinstance(resp, dict)
1393        return resp

Fetch pending bungie friend requests queue.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1395    async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1396        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1397        await self._request(
1398            RequestMethod.POST,
1399            f"Social/Friends/Requests/Accept/{member_id}",
1400            auth=access_token,
1401        )

Accepts a friend relationship with the target user. The user must be on your incoming friend request list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to accept.
async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1403    async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1404        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1405        await self._request(
1406            RequestMethod.POST,
1407            f"Social/Friends/Add/{member_id}",
1408            auth=access_token,
1409        )

Requests a friend relationship with the target user.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to send the request to.
async def decline_friend_request(self, access_token: str, /, member_id: int) -> None:
1411    async def decline_friend_request(
1412        self, access_token: str, /, member_id: int
1413    ) -> None:
1414        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1415        await self._request(
1416            RequestMethod.POST,
1417            f"Social/Friends/Requests/Decline/{member_id}",
1418            auth=access_token,
1419        )

Decline a friend request with the target user. The user must be in your incoming friend request list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to decline.
async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1421    async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1422        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1423        await self._request(
1424            RequestMethod.POST,
1425            f"Social/Friends/Remove/{member_id}",
1426            auth=access_token,
1427        )

Removes a friend from your friend list. The user must be in your friend list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to remove.
async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1429    async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1430        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1431        await self._request(
1432            RequestMethod.POST,
1433            f"Social/Friends/Requests/Remove/{member_id}",
1434            auth=access_token,
1435        )

Removes a friend from your friend list requests. The user must be in your outgoing request list.

.. note : This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to remove from the requested friend list.
async def approve_all_pending_group_users( self, access_token: str, /, group_id: int, message: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> None:
1437    async def approve_all_pending_group_users(
1438        self,
1439        access_token: str,
1440        /,
1441        group_id: int,
1442        message: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1443    ) -> None:
1444        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1445        await self._request(
1446            RequestMethod.POST,
1447            f"GroupV2/{group_id}/Members/ApproveAll",
1448            auth=access_token,
1449            json={"message": str(message)},
1450        )

Apporve all pending users for the given group id.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other Parameters
async def deny_all_pending_group_users( self, access_token: str, /, group_id: int, *, message: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> None:
1452    async def deny_all_pending_group_users(
1453        self,
1454        access_token: str,
1455        /,
1456        group_id: int,
1457        *,
1458        message: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1459    ) -> None:
1460        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1461        await self._request(
1462            RequestMethod.POST,
1463            f"GroupV2/{group_id}/Members/DenyAll",
1464            auth=access_token,
1465            json={"message": str(message)},
1466        )

Deny all pending users for the given group id.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other Parameters
async def add_optional_conversation( self, access_token: str, /, group_id: int, *, name: Union[aiobungie.UndefinedType, str] = UNDEFINED, security: Literal[0, 1] = 0) -> None:
1468    async def add_optional_conversation(
1469        self,
1470        access_token: str,
1471        /,
1472        group_id: int,
1473        *,
1474        name: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1475        security: typing.Literal[0, 1] = 0,
1476    ) -> None:
1477        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1478        payload = {"chatName": str(name), "chatSecurity": security}
1479        await self._request(
1480            RequestMethod.POST,
1481            f"GroupV2/{group_id}/OptionalConversations/Add",
1482            json=payload,
1483            auth=access_token,
1484        )

Add a new chat channel to a group.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other parameters

name: aiobungie.UndefinedOr[str] The chat name. Default to UNDEFINED security: typing.Literal[0, 1] The security level of the chat.

If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`
async def edit_optional_conversation( self, access_token: str, /, group_id: int, conversation_id: int, *, name: Union[aiobungie.UndefinedType, str] = UNDEFINED, security: Literal[0, 1] = 0, enable_chat: bool = False) -> None:
1486    async def edit_optional_conversation(
1487        self,
1488        access_token: str,
1489        /,
1490        group_id: int,
1491        conversation_id: int,
1492        *,
1493        name: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1494        security: typing.Literal[0, 1] = 0,
1495        enable_chat: bool = False,
1496    ) -> None:
1497        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1498        payload = {
1499            "chatEnabled": enable_chat,
1500            "chatName": str(name),
1501            "chatSecurity": security,
1502        }
1503        await self._request(
1504            RequestMethod.POST,
1505            f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}",
1506            json=payload,
1507            auth=access_token,
1508        )

Edit the settings of this chat channel.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
  • conversation_id (int): The conversation/chat id.
Other parameters

name: aiobungie.UndefinedOr[str] The new chat name. Default to UNDEFINED security: typing.Literal[0, 1] The new security level of the chat.

If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`

enable_chat : bool Whether to enable chatting or not. If set to True then chatting will be enabled. Otherwise it will be disabled.

async def transfer_item( self, access_token: str, /, item_id: int, item_hash: int, character_id: int, member_type: Union[int, aiobungie.MembershipType], *, stack_size: int = 1, vault: bool = False) -> None:
1510    async def transfer_item(
1511        self,
1512        access_token: str,
1513        /,
1514        item_id: int,
1515        item_hash: int,
1516        character_id: int,
1517        member_type: typedefs.IntAnd[enums.MembershipType],
1518        *,
1519        stack_size: int = 1,
1520        vault: bool = False,
1521    ) -> None:
1522        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1523        payload = {
1524            "characterId": character_id,
1525            "membershipType": int(member_type),
1526            "itemId": item_id,
1527            "itemReferenceHash": item_hash,
1528            "stackSize": stack_size,
1529            "transferToVault": vault,
1530        }
1531        await self._request(
1532            RequestMethod.POST,
1533            "Destiny2/Actions/Items/TransferItem",
1534            json=payload,
1535            auth=access_token,
1536        )

Transfer an item from / to your vault.

Notes
  • This method requires OAuth2: MoveEquipDestinyItems scope.
  • This method requires both item id and hash.
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item instance id you to transfer.
  • item_hash (int): The item hash.
  • character_id (int): The character id to transfer the item from/to.
  • member_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
  • stack_size (int): The item stack size.
  • valut (bool): Whether to trasnfer this item to your valut or not. Defaults to False.
async def pull_item( self, access_token: str, /, item_id: int, item_hash: int, character_id: int, member_type: Union[int, aiobungie.MembershipType], *, stack_size: int = 1, vault: bool = False) -> None:
1538    async def pull_item(
1539        self,
1540        access_token: str,
1541        /,
1542        item_id: int,
1543        item_hash: int,
1544        character_id: int,
1545        member_type: typedefs.IntAnd[enums.MembershipType],
1546        *,
1547        stack_size: int = 1,
1548        vault: bool = False,
1549    ) -> None:
1550        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1551        payload = {
1552            "characterId": character_id,
1553            "membershipType": int(member_type),
1554            "itemId": item_id,
1555            "itemReferenceHash": item_hash,
1556            "stackSize": stack_size,
1557            "transferToVault": vault,
1558        }
1559        await self._request(
1560            RequestMethod.POST,
1561            "Destiny2/Actions/Items/PullFromPostmaster",
1562            json=payload,
1563            auth=access_token,
1564        )

pull an item from the postmaster.

Notes
  • This method requires OAuth2: MoveEquipDestinyItems scope.
  • This method requires both item id and hash.
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item instance id to pull.
  • item_hash (int): The item hash.
  • character_id (int): The character id to pull the item to.
  • member_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
  • stack_size (int): The item stack size.
  • valut (bool): Whether to pill this item to your valut or not. Defaults to False.
async def fetch_fireteams( self, activity_type: Union[int, aiobungie.FireteamActivity], *, platform: Union[int, aiobungie.FireteamPlatform] = <FireteamPlatform.ANY: 0>, language: Union[aiobungie.FireteamLanguage, str] = <FireteamLanguage.ALL: >, date_range: Union[int, aiobungie.FireteamDate] = <FireteamDate.ALL: 0>, page: int = 0, slots_filter: int = 0) -> dict[str, typing.Any]:
1566    async def fetch_fireteams(
1567        self,
1568        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1569        *,
1570        platform: typedefs.IntAnd[
1571            fireteams.FireteamPlatform
1572        ] = fireteams.FireteamPlatform.ANY,
1573        language: typing.Union[
1574            fireteams.FireteamLanguage, str
1575        ] = fireteams.FireteamLanguage.ALL,
1576        date_range: typedefs.IntAnd[
1577            fireteams.FireteamDate
1578        ] = fireteams.FireteamDate.ALL,
1579        page: int = 0,
1580        slots_filter: int = 0,
1581    ) -> typedefs.JSONObject:
1582        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1583        resp = await self._request(
1584            RequestMethod.GET,
1585            f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}",  # noqa: E501 Line too long
1586        )
1587        assert isinstance(resp, dict)
1588        return resp

Fetch public Bungie fireteams with open slots.

Parameters
Other Parameters
Returns
async def fetch_avaliable_clan_fireteams( self, access_token: str, group_id: int, activity_type: Union[int, aiobungie.FireteamActivity], *, platform: Union[int, aiobungie.FireteamPlatform], language: Union[aiobungie.FireteamLanguage, str], date_range: Union[int, aiobungie.FireteamDate] = <FireteamDate.ALL: 0>, page: int = 0, public_only: bool = False, slots_filter: int = 0) -> dict[str, typing.Any]:
1590    async def fetch_avaliable_clan_fireteams(
1591        self,
1592        access_token: str,
1593        group_id: int,
1594        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1595        *,
1596        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1597        language: typing.Union[fireteams.FireteamLanguage, str],
1598        date_range: typedefs.IntAnd[
1599            fireteams.FireteamDate
1600        ] = fireteams.FireteamDate.ALL,
1601        page: int = 0,
1602        public_only: bool = False,
1603        slots_filter: int = 0,
1604    ) -> typedefs.JSONObject:
1605        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1606        resp = await self._request(
1607            RequestMethod.GET,
1608            f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}",  # noqa: E501
1609            json={"langFilter": str(language)},
1610            auth=access_token,
1611        )
1612        assert isinstance(resp, dict)
1613        return resp

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id of the fireteam.
  • activity_type (aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (aiobungie.typedefs.IntAnd[aiobungie.FireteamDate]): An integer to filter the date range of the returned fireteams. Defaults to aiobungie.FireteamDate.ALL.
  • page (int): The page number. By default its 0 which returns all available activities.
  • public_only (bool): If set to True, Then only public fireteams will be returned.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
async def fetch_clan_fireteam( self, access_token: str, fireteam_id: int, group_id: int) -> dict[str, typing.Any]:
1615    async def fetch_clan_fireteam(
1616        self, access_token: str, fireteam_id: int, group_id: int
1617    ) -> typedefs.JSONObject:
1618        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1619        resp = await self._request(
1620            RequestMethod.GET,
1621            f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}",
1622            auth=access_token,
1623        )
1624        assert isinstance(resp, dict)
1625        return resp

Fetch a specific clan fireteam.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch the fireteam from.
  • fireteam_id (int): The fireteam id to fetch.
Returns
async def fetch_my_clan_fireteams( self, access_token: str, group_id: int, *, include_closed: bool = True, platform: Union[int, aiobungie.FireteamPlatform], language: Union[aiobungie.FireteamLanguage, str], filtered: bool = True, page: int = 0) -> dict[str, typing.Any]:
1627    async def fetch_my_clan_fireteams(
1628        self,
1629        access_token: str,
1630        group_id: int,
1631        *,
1632        include_closed: bool = True,
1633        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1634        language: typing.Union[fireteams.FireteamLanguage, str],
1635        filtered: bool = True,
1636        page: int = 0,
1637    ) -> typedefs.JSONObject:
1638        payload = {"groupFilter": filtered, "langFilter": str(language)}
1639        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1640        resp = await self._request(
1641            RequestMethod.GET,
1642            f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}",
1643            json=payload,
1644            auth=access_token,
1645        )
1646        assert isinstance(resp, dict)
1647        return resp

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch.
Other Parameters
  • include_closed (bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True.
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • filtered (bool): If set to True, it will filter by clan. Otherwise not. Default is True.
  • page (int): The page number. By default its 0 which returns all available activities.
Returns
async def fetch_private_clan_fireteams(self, access_token: str, group_id: int, /) -> int:
1649    async def fetch_private_clan_fireteams(
1650        self, access_token: str, group_id: int, /
1651    ) -> int:
1652        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1653        resp = await self._request(
1654            RequestMethod.GET,
1655            f"Fireteam/Clan/{group_id}/ActiveCount",
1656            auth=access_token,
1657        )
1658        assert isinstance(resp, int)
1659        return resp

Fetch the active count of the clan fireteams that are only private.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id.
Returns
  • int: The active fireteams count. Max value returned is 25.
async def fetch_post_activity(self, instance_id: int, /) -> dict[str, typing.Any]:
1661    async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject:
1662        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1663        resp = await self._request(
1664            RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}"
1665        )
1666        assert isinstance(resp, dict)
1667        return resp

Fetch a post activity details.

Parameters
  • instance_id (int): The activity instance id.
Returns
async def search_entities( self, name: str, entity_type: str, *, page: int = 0) -> dict[str, typing.Any]:
1669    async def search_entities(
1670        self, name: str, entity_type: str, *, page: int = 0
1671    ) -> typedefs.JSONObject:
1672        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1673        resp = await self._request(
1674            RequestMethod.GET,
1675            f"Destiny2/Armory/Search/{entity_type}/{name}/",
1676            json={"page": page},
1677        )
1678        assert isinstance(resp, dict)
1679        return resp

Search for Destiny2 entities given a name and its type.

Parameters
  • name (str): The name of the entity, i.e., Thunderlord, One thousand voices.
  • entity_type (str): The type of the entity, AKA Definition, For an example DestinyInventoryItemDefinition
Other Parameters
  • page (int): An optional page to return. Default to 0.
Returns
async def fetch_unique_weapon_history( self, membership_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
1681    async def fetch_unique_weapon_history(
1682        self,
1683        membership_id: int,
1684        character_id: int,
1685        membership_type: typedefs.IntAnd[enums.MembershipType],
1686    ) -> typedefs.JSONObject:
1687        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1688        resp = await self._request(
1689            RequestMethod.GET,
1690            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/",
1691        )
1692        assert isinstance(resp, dict)
1693        return resp

Fetch details about unique weapon usage for a character. Includes all exotics.

Parameters
Returns
async def fetch_item( self, member_id: int, item_id: int, membership_type: Union[int, aiobungie.MembershipType], components: list[aiobungie.ComponentType]) -> dict[str, typing.Any]:
1695    async def fetch_item(
1696        self,
1697        member_id: int,
1698        item_id: int,
1699        membership_type: typedefs.IntAnd[enums.MembershipType],
1700        components: list[enums.ComponentType],
1701    ) -> typedefs.JSONObject:
1702        collector = _collect_components(components)
1703        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1704        resp = await self._request(
1705            RequestMethod.GET,
1706            f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}",
1707        )
1708        assert isinstance(resp, dict)
1709        return resp

Fetch an instanced Destiny 2 item's details.

Parameters
Returns
async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> dict[str, typing.Any]:
1711    async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject:
1712        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1713        resp = await self._request(
1714            RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/"
1715        )
1716        assert isinstance(resp, dict)
1717        return resp

Fetch the weekly reward state for a clan.

Parameters
  • clan_id (int): The clan id.
Returns
async def fetch_available_locales(self) -> dict[str, typing.Any]:
1719    async def fetch_available_locales(self) -> typedefs.JSONObject:
1720        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1721        resp = await self._request(
1722            RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/"
1723        )
1724        assert isinstance(resp, dict)
1725        return resp

Fetch available locales at Bungie.

Returns
async def fetch_common_settings(self) -> dict[str, typing.Any]:
1727    async def fetch_common_settings(self) -> typedefs.JSONObject:
1728        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1729        resp = await self._request(RequestMethod.GET, "Settings")
1730        assert isinstance(resp, dict)
1731        return resp

Fetch the common settings used by Bungie's envirotment.

Returns
async def fetch_user_systems_overrides(self) -> dict[str, typing.Any]:
1733    async def fetch_user_systems_overrides(self) -> typedefs.JSONObject:
1734        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1735        resp = await self._request(RequestMethod.GET, "UserSystemOverrides")
1736        assert isinstance(resp, dict)
1737        return resp

Fetch a user's specific system overrides.

Returns
async def fetch_global_alerts(self, *, include_streaming: bool = False) -> list[typing.Any]:
1739    async def fetch_global_alerts(
1740        self, *, include_streaming: bool = False
1741    ) -> typedefs.JSONArray:
1742        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1743        resp = await self._request(
1744            RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}"
1745        )
1746        assert isinstance(resp, list)
1747        return resp

Fetch any active global alerts.

Parameters
  • include_streaming (bool): If True, the returned results will include streaming alerts. Default is False.
Returns
async def awainitialize_request( self, access_token: str, type: Literal[0, 1], membership_type: Union[int, aiobungie.MembershipType], /, *, affected_item_id: Optional[int] = None, character_id: Optional[int] = None) -> dict[str, typing.Any]:
1749    async def awainitialize_request(
1750        self,
1751        access_token: str,
1752        type: typing.Literal[0, 1],
1753        membership_type: typedefs.IntAnd[enums.MembershipType],
1754        /,
1755        *,
1756        affected_item_id: typing.Optional[int] = None,
1757        character_id: typing.Optional[int] = None,
1758    ) -> typedefs.JSONObject:
1759        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1760
1761        body = {"type": type, "membershipType": int(membership_type)}
1762
1763        if affected_item_id is not None:
1764            body["affectedItemId"] = affected_item_id
1765
1766        if character_id is not None:
1767            body["characterId"] = character_id
1768
1769        resp = await self._request(
1770            RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token
1771        )
1772        assert isinstance(resp, dict)
1773        return resp

Initialize a request to perform an advanced write action.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • type (typing.Literal[0, 1]): Type of the advanced write action. Its either 0 or 1. If set to 0 that means it None. Otherwise if 1 that means its insert plugs.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type of the account to modify.
Other Parameters
  • affected_item_id (typing.Optional[int]): Item instance ID the action shall be applied to. This is optional for all but a new AwaType values.
  • character_id (typing.Optional[int]): The Destiny character ID to perform this action on.
Returns
async def awaget_action_token(self, access_token: str, correlation_id: str, /) -> dict[str, typing.Any]:
1775    async def awaget_action_token(
1776        self, access_token: str, correlation_id: str, /
1777    ) -> typedefs.JSONObject:
1778        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1779        resp = await self._request(
1780            RequestMethod.POST,
1781            f"Destiny2/Awa/GetActionToken/{correlation_id}",
1782            auth=access_token,
1783        )
1784        assert isinstance(resp, dict)
1785        return resp

Returns the action token if user approves the request.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • correlation_id (str): The identifier for the advanced write action request.
Returns
async def awa_provide_authorization_result( self, access_token: str, selection: int, correlation_id: str, nonce: collections.abc.MutableSequence[typing.Union[str, bytes]]) -> int:
1787    async def awa_provide_authorization_result(
1788        self,
1789        access_token: str,
1790        selection: int,
1791        correlation_id: str,
1792        nonce: collections.MutableSequence[typing.Union[str, bytes]],
1793    ) -> int:
1794        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1795
1796        body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce}
1797
1798        resp = await self._request(
1799            RequestMethod.POST,
1800            "Destiny2/Awa/AwaProvideAuthorizationResult",
1801            json=body,
1802            auth=access_token,
1803        )
1804        assert isinstance(resp, int)
1805        return resp

Provide the result of the user interaction. Called by the Bungie Destiny App to approve or reject a request.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • selection (int): Indication of the selection the user has made (Approving or rejecting the action)
  • correlation_id (str): Correlation ID of the request.
  • nonce (collections.MutableSequence[str, bytes]): Secret nonce received via the PUSH notification.
Returns
  • int: ...
async def fetch_vendors( self, access_token: str, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], /, components: list[aiobungie.ComponentType], filter: Optional[int] = None) -> dict[str, typing.Any]:
1807    async def fetch_vendors(
1808        self,
1809        access_token: str,
1810        character_id: int,
1811        membership_id: int,
1812        membership_type: typedefs.IntAnd[enums.MembershipType],
1813        /,
1814        components: list[enums.ComponentType],
1815        filter: typing.Optional[int] = None,
1816    ) -> typedefs.JSONObject:
1817        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1818        components_ = _collect_components(components)
1819        route = (
1820            f"Destiny2/{int(membership_type)}/Profile/{membership_id}"
1821            f"/Character/{character_id}/Vendors/?components={components_}"
1822        )
1823
1824        if filter is not None:
1825            route = route + f"&filter={filter}"
1826
1827        resp = await self._request(
1828            RequestMethod.GET,
1829            route,
1830            auth=access_token,
1831        )
1832        assert isinstance(resp, dict)
1833        return resp

Get currently available vendors from the list of vendors that can possibly have rotating inventory.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • character_id (int): The character ID to return the vendor info for.
  • membership_id (int): The Destiny membership id to return the vendor info for.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for.
  • components (list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Other Parameters
  • filter (int): Filters the type of items returned from the vendor. This can be left to None.
Returns
async def fetch_vendor( self, access_token: str, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], vendor_hash: int, /, components: list[aiobungie.ComponentType]) -> dict[str, typing.Any]:
1835    async def fetch_vendor(
1836        self,
1837        access_token: str,
1838        character_id: int,
1839        membership_id: int,
1840        membership_type: typedefs.IntAnd[enums.MembershipType],
1841        vendor_hash: int,
1842        /,
1843        components: list[enums.ComponentType],
1844    ) -> typedefs.JSONObject:
1845        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1846        components_ = _collect_components(components)
1847        resp = await self._request(
1848            RequestMethod.GET,
1849            (
1850                f"Platform/Destiny2/{int(membership_type)}/Profile/{membership_id}"
1851                f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}"
1852            ),
1853            auth=access_token,
1854        )
1855        assert isinstance(resp, dict)
1856        return resp

Fetch details for a specific vendor.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • character_id (int): The character ID to return the vendor info for.
  • membership_id (int): The Destiny membership id to return the vendor info for.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for.
  • vendor_hash (int): The vendor hash to return the details for.
  • components (list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Returns
async def fetch_application_api_usage( self, access_token: str, application_id: int, /, *, start: Optional[datetime.datetime] = None, end: Optional[datetime.datetime] = None) -> dict[str, typing.Any]:
1858    async def fetch_application_api_usage(
1859        self,
1860        access_token: str,
1861        application_id: int,
1862        /,
1863        *,
1864        start: typing.Optional[datetime.datetime] = None,
1865        end: typing.Optional[datetime.datetime] = None,
1866    ) -> typedefs.JSONObject:
1867
1868        end_date, start_date = time.parse_date_range(end, start)
1869        resp = await self._request(
1870            RequestMethod.GET,
1871            f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}",
1872            auth=access_token,
1873        )
1874        assert isinstance(resp, dict)
1875        return resp

Fetch a Bungie application's API usage.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • application_id (int): The application id to get.
Other Parameters
  • start (typing.Optional[datetime.datetime]): A datetime object can be used to collect the start of the application usage. This is limited and can go back to 30 days maximum.

    If this is left to None. It will return the last 24 hours.

  • end (typing.Optional[datetime.datetime]): A datetime object can be used to collect the end of the application usage.

    If this is left to None. It will return now.

Example
import datetime

# Fetch data from 2021 Dec 10th to 2021 Dec 20th
await fetch_application_api_usage(
    start=datetime.datetime(2021, 12, 10), end=datetime.datetime(2021, 12, 20)
)
Returns
async def fetch_bungie_applications(self) -> list[typing.Any]:
1877    async def fetch_bungie_applications(self) -> typedefs.JSONArray:
1878        resp = await self._request(RequestMethod.GET, "App/FirstParty")
1879        assert isinstance(resp, list)
1880        return resp

Fetch details for applications created by Bungie.

Returns
async def fetch_content_type(self, type: str, /) -> dict[str, typing.Any]:
1882    async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject:
1883        resp = await self._request(RequestMethod.GET, f"Content/GetContentType/{type}/")
1884        assert isinstance(resp, dict)
1885        return resp
async def fetch_content_by_id( self, id: int, locale: str, /, *, head: bool = False) -> dict[str, typing.Any]:
1887    async def fetch_content_by_id(
1888        self, id: int, locale: str, /, *, head: bool = False
1889    ) -> typedefs.JSONObject:
1890        resp = await self._request(
1891            RequestMethod.GET,
1892            f"Content/GetContentById/{id}/{locale}/",
1893            json={"head": head},
1894        )
1895        assert isinstance(resp, dict)
1896        return resp
async def fetch_content_by_tag_and_type( self, locale: str, tag: str, type: str, *, head: bool = False) -> dict[str, typing.Any]:
1898    async def fetch_content_by_tag_and_type(
1899        self, locale: str, tag: str, type: str, *, head: bool = False
1900    ) -> typedefs.JSONObject:
1901        resp = await self._request(
1902            RequestMethod.GET,
1903            f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/",
1904            json={"head": head},
1905        )
1906        assert isinstance(resp, dict)
1907        return resp
async def search_content_with_text( self, locale: str, /, content_type: str, search_text: str, tag: str, *, page: Union[aiobungie.UndefinedType, int] = UNDEFINED, source: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> dict[str, typing.Any]:
1909    async def search_content_with_text(
1910        self,
1911        locale: str,
1912        /,
1913        content_type: str,
1914        search_text: str,
1915        tag: str,
1916        *,
1917        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
1918        source: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1919    ) -> typedefs.JSONObject:
1920
1921        body: typedefs.JSONObject = {}
1922
1923        body["ctype"] = content_type
1924        body["searchtext"] = search_text
1925        body["tag"] = tag
1926
1927        if page is not undefined.UNDEFINED:
1928            body["currentpage"] = page
1929        else:
1930            body["currentpage"] = 1
1931
1932        if source is not undefined.UNDEFINED:
1933            body["source"] = source
1934        else:
1935            source = ""
1936        resp = await self._request(
1937            RequestMethod.GET, f"Content/Search/{locale}/", json=body
1938        )
1939        assert isinstance(resp, dict)
1940        return resp
async def search_content_by_tag_and_type( self, locale: str, tag: str, type: str, *, page: Union[aiobungie.UndefinedType, int] = UNDEFINED) -> dict[str, typing.Any]:
1942    async def search_content_by_tag_and_type(
1943        self,
1944        locale: str,
1945        tag: str,
1946        type: str,
1947        *,
1948        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
1949    ) -> typedefs.JSONObject:
1950        body: typedefs.JSONObject = {}
1951        body["currentpage"] = 1 if page is undefined.UNDEFINED else page
1952        resp = await self._request(
1953            RequestMethod.GET,
1954            f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/",
1955            json=body,
1956        )
1957        assert isinstance(resp, dict)
1958        return resp
async def search_help_articles(self, text: str, size: str, /) -> dict[str, typing.Any]:
1960    async def search_help_articles(
1961        self, text: str, size: str, /
1962    ) -> typedefs.JSONObject:
1963        resp = await self._request(
1964            RequestMethod.GET, f"Content/SearchHelpArticles/{text}/{size}/"
1965        )
1966        assert isinstance(resp, dict)
1967        return resp
async def fetch_topics_page( self, category_filter: int, group: int, date_filter: int, sort: Union[str, bytes], *, page: Union[aiobungie.UndefinedType, int] = UNDEFINED, locales: Union[aiobungie.UndefinedType, collections.abc.Iterable[str]] = UNDEFINED, tag_filter: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> dict[str, typing.Any]:
1969    async def fetch_topics_page(
1970        self,
1971        category_filter: int,
1972        group: int,
1973        date_filter: int,
1974        sort: typing.Union[str, bytes],
1975        *,
1976        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
1977        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.UNDEFINED,
1978        tag_filter: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1979    ) -> typedefs.JSONObject:
1980
1981        body: typedefs.JSONObject = {}
1982        if locales is not undefined.UNDEFINED:
1983            body["locales"] = ",".join(str(locales))
1984        else:
1985            body["locales"] = ",".join([])
1986
1987        if tag_filter is not undefined.UNDEFINED:
1988            body["tagstring"] = tag_filter
1989        else:
1990            body["tagstring"] = ""
1991
1992        page = 0 if page is not undefined.UNDEFINED else page
1993
1994        resp = await self._request(
1995            RequestMethod.GET,
1996            f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/",
1997            json=body,
1998        )
1999        assert isinstance(resp, dict)
2000        return resp
async def fetch_core_topics_page( self, category_filter: int, date_filter: int, sort: Union[str, bytes], *, page: Union[aiobungie.UndefinedType, int] = UNDEFINED, locales: Union[aiobungie.UndefinedType, collections.abc.Iterable[str]] = UNDEFINED) -> dict[str, typing.Any]:
2002    async def fetch_core_topics_page(
2003        self,
2004        category_filter: int,
2005        date_filter: int,
2006        sort: typing.Union[str, bytes],
2007        *,
2008        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
2009        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.UNDEFINED,
2010    ) -> typedefs.JSONObject:
2011        body: typedefs.JSONObject = {}
2012
2013        if locales is not undefined.UNDEFINED:
2014            body["locales"] = ",".join(str(locales))
2015        else:
2016            body["locales"] = ",".join([])
2017
2018        resp = await self._request(
2019            RequestMethod.GET,
2020            f"Forum/GetCoreTopicsPaged/{0 if page is undefined.UNDEFINED else page}"
2021            f"/{sort!s}/{date_filter}/{category_filter}/",
2022            json=body,
2023        )
2024        assert isinstance(resp, dict)
2025        return resp
async def fetch_posts_threaded_page( self, parent_post: bool, page: int, page_size: int, parent_post_id: int, reply_size: int, root_thread_mode: bool, sort_mode: int, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2027    async def fetch_posts_threaded_page(
2028        self,
2029        parent_post: bool,
2030        page: int,
2031        page_size: int,
2032        parent_post_id: int,
2033        reply_size: int,
2034        root_thread_mode: bool,
2035        sort_mode: int,
2036        show_banned: typing.Optional[str] = None,
2037    ) -> typedefs.JSONObject:
2038        resp = await self._request(
2039            RequestMethod.GET,
2040            f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/"
2041            f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/",
2042            json={"showbanned": show_banned},
2043        )
2044        assert isinstance(resp, dict)
2045        return resp
async def fetch_posts_threaded_page_from_child( self, child_id: bool, page: int, page_size: int, reply_size: int, root_thread_mode: bool, sort_mode: int, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2047    async def fetch_posts_threaded_page_from_child(
2048        self,
2049        child_id: bool,
2050        page: int,
2051        page_size: int,
2052        reply_size: int,
2053        root_thread_mode: bool,
2054        sort_mode: int,
2055        show_banned: typing.Optional[str] = None,
2056    ) -> typedefs.JSONObject:
2057        resp = await self._request(
2058            RequestMethod.GET,
2059            f"Forum/GetPostsThreadedPagedFromChild/{child_id}/"
2060            f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/",
2061            json={"showbanned": show_banned},
2062        )
2063        assert isinstance(resp, dict)
2064        return resp
async def fetch_post_and_parent( self, child_id: int, /, *, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2066    async def fetch_post_and_parent(
2067        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2068    ) -> typedefs.JSONObject:
2069        resp = await self._request(
2070            RequestMethod.GET,
2071            f"Forum/GetPostAndParent/{child_id}/",
2072            json={"showbanned": show_banned},
2073        )
2074        assert isinstance(resp, dict)
2075        return resp
async def fetch_posts_and_parent_awaiting( self, child_id: int, /, *, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2077    async def fetch_posts_and_parent_awaiting(
2078        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2079    ) -> typedefs.JSONObject:
2080        resp = await self._request(
2081            RequestMethod.GET,
2082            f"Forum/GetPostAndParentAwaitingApproval/{child_id}/",
2083            json={"showbanned": show_banned},
2084        )
2085        assert isinstance(resp, dict)
2086        return resp
async def fetch_topic_for_content(self, content_id: int, /) -> int:
2088    async def fetch_topic_for_content(self, content_id: int, /) -> int:
2089        resp = await self._request(
2090            RequestMethod.GET, f"Forum/GetTopicForContent/{content_id}/"
2091        )
2092        assert isinstance(resp, int)
2093        return resp
async def fetch_forum_tag_suggestions(self, partial_tag: str, /) -> dict[str, typing.Any]:
2095    async def fetch_forum_tag_suggestions(
2096        self, partial_tag: str, /
2097    ) -> typedefs.JSONObject:
2098        resp = await self._request(
2099            RequestMethod.GET,
2100            "Forum/GetForumTagSuggestions/",
2101            json={"partialtag": partial_tag},
2102        )
2103        assert isinstance(resp, dict)
2104        return resp
async def fetch_poll(self, topic_id: int, /) -> dict[str, typing.Any]:
2106    async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject:
2107        resp = await self._request(RequestMethod.GET, f"Forum/Poll/{topic_id}/")
2108        assert isinstance(resp, dict)
2109        return resp
async def fetch_recuirement_thread_summaries(self) -> list[typing.Any]:
2111    async def fetch_recuirement_thread_summaries(self) -> typedefs.JSONArray:
2112        resp = await self._request(RequestMethod.POST, "Forum/Recruit/Summaries/")
2113        assert isinstance(resp, list)
2114        return resp
async def fetch_available_avatars(self) -> collections.abc.Mapping[str, int]:
2132    async def fetch_available_avatars(self) -> collections.Mapping[str, int]:
2133        resp = await self._request(RequestMethod.GET, "GroupV2/GetAvailableAvatars/")
2134        assert isinstance(resp, dict)
2135        return resp
async def fetch_user_clan_invite_setting( self, access_token: str, /, membership_type: Union[int, aiobungie.MembershipType]) -> bool:
2137    async def fetch_user_clan_invite_setting(
2138        self,
2139        access_token: str,
2140        /,
2141        membership_type: typedefs.IntAnd[enums.MembershipType],
2142    ) -> bool:
2143        resp = await self._request(
2144            RequestMethod.GET,
2145            f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/",
2146            auth=access_token,
2147        )
2148        assert isinstance(resp, bool)
2149        return resp
async def fetch_banned_group_members( self, access_token: str, group_id: int, /, *, page: int = 1) -> dict[str, typing.Any]:
2151    async def fetch_banned_group_members(
2152        self, access_token: str, group_id: int, /, *, page: int = 1
2153    ) -> typedefs.JSONObject:
2154        resp = await self._request(
2155            RequestMethod.GET,
2156            f"GroupV2/{group_id}/Banned/?currentpage={page}",
2157            auth=access_token,
2158        )
2159        assert isinstance(resp, dict)
2160        return resp
async def fetch_pending_group_memberships( self, access_token: str, group_id: int, /, *, current_page: int = 1) -> dict[str, typing.Any]:
2162    async def fetch_pending_group_memberships(
2163        self, access_token: str, group_id: int, /, *, current_page: int = 1
2164    ) -> typedefs.JSONObject:
2165        resp = await self._request(
2166            RequestMethod.GET,
2167            f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}",
2168            auth=access_token,
2169        )
2170        assert isinstance(resp, dict)
2171        return resp
async def fetch_invited_group_memberships( self, access_token: str, group_id: int, /, *, current_page: int = 1) -> dict[str, typing.Any]:
2173    async def fetch_invited_group_memberships(
2174        self, access_token: str, group_id: int, /, *, current_page: int = 1
2175    ) -> typedefs.JSONObject:
2176        resp = await self._request(
2177            RequestMethod.GET,
2178            f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}",
2179            auth=access_token,
2180        )
2181        assert isinstance(resp, dict)
2182        return resp
async def invite_member_to_group( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], *, message: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> dict[str, typing.Any]:
2184    async def invite_member_to_group(
2185        self,
2186        access_token: str,
2187        /,
2188        group_id: int,
2189        membership_id: int,
2190        membership_type: typedefs.IntAnd[enums.MembershipType],
2191        *,
2192        message: undefined.UndefinedOr[str] = undefined.UNDEFINED,
2193    ) -> typedefs.JSONObject:
2194        resp = await self._request(
2195            RequestMethod.POST,
2196            f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/",
2197            auth=access_token,
2198            json={"message": str(message)},
2199        )
2200        assert isinstance(resp, dict)
2201        return resp
async def cancel_group_member_invite( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
2203    async def cancel_group_member_invite(
2204        self,
2205        access_token: str,
2206        /,
2207        group_id: int,
2208        membership_id: int,
2209        membership_type: typedefs.IntAnd[enums.MembershipType],
2210    ) -> typedefs.JSONObject:
2211        resp = await self._request(
2212            RequestMethod.POST,
2213            f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/",
2214            auth=access_token,
2215        )
2216        assert isinstance(resp, dict)
2217        return resp
async def fetch_historical_definition(self) -> dict[str, typing.Any]:
2219    async def fetch_historical_definition(self) -> typedefs.JSONObject:
2220        resp = await self._request(RequestMethod.GET, "Destiny2/Stats/Definition/")
2221        assert isinstance(resp, dict)
2222        return resp
async def fetch_historical_stats( self, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], day_start: datetime.datetime, day_end: datetime.datetime, groups: list[typing.Union[int, aiobungie.internal.enums.StatsGroupType]], modes: collections.abc.Sequence[typing.Union[int, aiobungie.GameMode]], *, period_type: aiobungie.internal.enums.PeriodType = <PeriodType.ALL_TIME: 2>) -> dict[str, typing.Any]:
2224    async def fetch_historical_stats(
2225        self,
2226        character_id: int,
2227        membership_id: int,
2228        membership_type: typedefs.IntAnd[enums.MembershipType],
2229        day_start: datetime.datetime,
2230        day_end: datetime.datetime,
2231        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2232        modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]],
2233        *,
2234        period_type: enums.PeriodType = enums.PeriodType.ALL_TIME,
2235    ) -> typedefs.JSONObject:
2236
2237        end, start = time.parse_date_range(day_end, day_start)
2238        resp = await self._request(
2239            RequestMethod.GET,
2240            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/",
2241            json={
2242                "dayend": end,
2243                "daystart": start,
2244                "groups": [str(int(group)) for group in groups],
2245                "modes": [str(int(mode)) for mode in modes],
2246                "periodType": int(period_type),
2247            },
2248        )
2249        assert isinstance(resp, dict)
2250        return resp

Fetch historical stats for a specific membership character.

Parameters
  • character_id (int): The character ID to return the stats for.
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
  • day_start (datetime.datetime): The start of the day to return the stats for.
  • day_end (datetime.datetime): The end of the day to return the stats for.
  • groups (list[aiobungie.StatsGroupType]): A list of stats groups to return.
  • modes (list[aiobungie.GameMode | int]): A list of game modes to return.
  • period_type (aiobungie.enums.PeriodType): The period type to return the stats for. This will return ALL_TIME by default if not modified.
Returns
async def fetch_historical_stats_for_account( self, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], groups: list[typing.Union[int, aiobungie.internal.enums.StatsGroupType]]) -> dict[str, typing.Any]:
2252    async def fetch_historical_stats_for_account(
2253        self,
2254        membership_id: int,
2255        membership_type: typedefs.IntAnd[enums.MembershipType],
2256        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2257    ) -> typedefs.JSONObject:
2258        resp = await self._request(
2259            RequestMethod.GET,
2260            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/",
2261            json={"groups": [str(int(group)) for group in groups]},
2262        )
2263        assert isinstance(resp, dict)
2264        return resp

Fetch historical stats for an account's membership.

Parameters
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
  • groups (list[aiobungie.StatsGroupType]): A list of stats groups to return.
Returns
async def fetch_aggregated_activity_stats( self, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], /) -> dict[str, typing.Any]:
2266    async def fetch_aggregated_activity_stats(
2267        self,
2268        character_id: int,
2269        membership_id: int,
2270        membership_type: typedefs.IntAnd[enums.MembershipType],
2271        /,
2272    ) -> typedefs.JSONObject:
2273        resp = await self._request(
2274            RequestMethod.GET,
2275            f"Destiny2/{int(membership_type)}/Account/{membership_id}/"
2276            f"Character/{character_id}/Stats/AggregateActivityStats/",
2277        )
2278        assert isinstance(resp, dict)
2279        return resp

Fetch aggregated activity stats for a specific membership character.

Parameters
  • character_id (int): The character ID to return the stats for.
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
Returns
class RESTPool:
196class RESTPool:
197    """Pool of `RESTClient` instances.
198
199    This allows to create multiple instances of `RESTClient`s that can be acquired
200    which share the same config and metadata.
201
202    Example
203    -------
204    ```py
205    import aiobungie
206    import asyncio
207
208    client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret')
209
210    # Using a context manager to acquire an instance
211    # of the pool and close the connection after finishing.
212
213    async def first() -> str:
214        async with client_pool.acquire() as client:
215            return client.build_oauth2_url()
216
217    async def second() -> None:
218        async with client_pool.acquire() as client:
219            new_tokens = await client.refresh_access_token("token")
220            client.metadata['tokens'] = new_tokens
221
222    # Client instances are independent from first and second.
223    await asyncio.gather(first(), second())
224    ```
225
226    Parameters
227    ----------
228    token : `str`
229        A valid application token from Bungie's developer portal.
230
231    Other Parameters
232    ----------------
233    max_retries : `int`
234        The max retries number to retry if the request hit a `5xx` status code.
235    client_secret : `typing.Optional[str]`
236        An optional application client secret,
237        This is only needed if you're fetching OAuth2 tokens with this client.
238    client_id : `typing.Optional[int]`
239        An optional application client id,
240        This is only needed if you're fetching OAuth2 tokens with this client.
241    enable_debugging : `bool | str`
242        Whether to enable logging responses or not.
243
244    Logging Levels
245    --------------
246    * `False`: This will disable logging.
247    * `True`: This will set the level to `DEBUG` and enable logging minimal information.
248    Like the response status, route, taken time and so on.
249    * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information.
250    """
251
252    __slots__ = (
253        "_token",
254        "_max_retries",
255        "_client_secret",
256        "_client_id",
257        "_metadata",
258        "_enable_debug",
259        "_client_session",
260    )
261
262    # Looks like mypy doesn't like this.
263    if typing.TYPE_CHECKING:
264        _enable_debug: typing.Union[typing.Literal["TRACE"], bool, int]
265
266    def __init__(
267        self,
268        token: str,
269        /,
270        *,
271        client_secret: typing.Optional[str] = None,
272        client_id: typing.Optional[int] = None,
273        client_session: typing.Optional[aiohttp.ClientSession] = None,
274        max_retries: int = 4,
275        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
276    ) -> None:
277        self._client_secret = client_secret
278        self._client_id = client_id
279        self._token: str = token
280        self._max_retries = max_retries
281        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
282        self._enable_debug = enable_debugging
283        self._client_session = client_session
284
285    @property
286    def client_id(self) -> typing.Optional[int]:
287        return self._client_id
288
289    @property
290    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
291        """Pool's Metadata. This is different from client instance metadata."""
292        return self._metadata
293
294    @typing.final
295    def acquire(self) -> RESTClient:
296        """Acquires a new `RESTClient` instance from this REST pool.
297
298        Returns
299        -------
300        `RESTClient`
301            An instance of a REST client.
302        """
303        return RESTClient(
304            self._token,
305            client_secret=self._client_secret,
306            client_id=self._client_id,
307            max_retries=self._max_retries,
308            enable_debugging=self._enable_debug,
309            client_session=self._client_session,
310        )

Pool of RESTClient instances.

This allows to create multiple instances of RESTClients that can be acquired which share the same config and metadata.

Example
import aiobungie
import asyncio

client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret')

# Using a context manager to acquire an instance
# of the pool and close the connection after finishing.

async def first() -> str:
    async with client_pool.acquire() as client:
        return client.build_oauth2_url()

async def second() -> None:
    async with client_pool.acquire() as client:
        new_tokens = await client.refresh_access_token("token")
        client.metadata['tokens'] = new_tokens

# Client instances are independent from first and second.
await asyncio.gather(first(), second())
Parameters
  • token (str): A valid application token from Bungie's developer portal.
Other Parameters
  • max_retries (int): The max retries number to retry if the request hit a 5xx status code.
  • client_secret (typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client.
  • client_id (typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
  • enable_debugging (bool | str): Whether to enable logging responses or not.
Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information. Like the response status, route, taken time and so on.
  • "TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
RESTPool( token: str, /, *, client_secret: Optional[str] = None, client_id: Optional[int] = None, client_session: Optional[aiohttp.client.ClientSession] = None, max_retries: int = 4, enable_debugging: Union[Literal['TRACE'], bool, int] = False)
266    def __init__(
267        self,
268        token: str,
269        /,
270        *,
271        client_secret: typing.Optional[str] = None,
272        client_id: typing.Optional[int] = None,
273        client_session: typing.Optional[aiohttp.ClientSession] = None,
274        max_retries: int = 4,
275        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
276    ) -> None:
277        self._client_secret = client_secret
278        self._client_id = client_id
279        self._token: str = token
280        self._max_retries = max_retries
281        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
282        self._enable_debug = enable_debugging
283        self._client_session = client_session
metadata: collections.abc.MutableMapping[typing.Any, typing.Any]

Pool's Metadata. This is different from client instance metadata.

@typing.final
def acquire(self) -> aiobungie.RESTClient:
294    @typing.final
295    def acquire(self) -> RESTClient:
296        """Acquires a new `RESTClient` instance from this REST pool.
297
298        Returns
299        -------
300        `RESTClient`
301            An instance of a REST client.
302        """
303        return RESTClient(
304            self._token,
305            client_secret=self._client_secret,
306            client_id=self._client_id,
307            max_retries=self._max_retries,
308            enable_debugging=self._enable_debug,
309            client_session=self._client_session,
310        )

Acquires a new RESTClient instance from this REST pool.

Returns
@typing.final
class Race(builtins.int, aiobungie.Enum):
493@typing.final
494class Race(int, Enum):
495    """An Enum for Destiny races."""
496
497    HUMAN = 0
498    AWOKEN = 1
499    EXO = 2
500    UNKNOWN = 3

An Enum for Destiny races.

HUMAN = <Race.HUMAN: 0>
AWOKEN = <Race.AWOKEN: 1>
EXO = <Race.EXO: 2>
UNKNOWN = <Race.UNKNOWN: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Raid(builtins.int, aiobungie.Enum):
143@typing.final
144class Raid(int, Enum):
145    """An Enum for all available raids in Destiny 2."""
146
147    DSC = 910380154
148    """Deep Stone Crypt"""
149
150    LW = 2122313384
151    """Last Wish"""
152
153    VOG = 3881495763
154    """Normal Valut of Glass"""
155
156    GOS = 3458480158
157    """Garden Of Salvation"""

An Enum for all available raids in Destiny 2.

DSC = <Raid.DSC: 910380154>

Deep Stone Crypt

LW = <Raid.LW: 2122313384>

Last Wish

VOG = <Raid.VOG: 3881495763>

Normal Valut of Glass

GOS = <Raid.GOS: 3458480158>

Garden Of Salvation

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class RateLimitedError(aiobungie.HTTPError):
253@attrs.define(auto_exc=True)
254class RateLimitedError(HTTPError):
255    """Raised when too many request status code is returned."""
256
257    http_status: http.HTTPStatus = attrs.field(
258        default=http.HTTPStatus.TOO_MANY_REQUESTS, init=False
259    )
260    """The request response http status."""
261
262    url: typedefs.StrOrURL
263    """The URL/endpoint caused this error."""
264
265    body: typing.Any
266    """The response body."""
267
268    retry_after: float = attrs.field(default=0.0)
269    """The amount of seconds you need to wait before retrying to requests."""
270
271    message: str = attrs.field(init=False)
272    """A Bungie human readable message describes the cause of the error."""
273
274    @message.default  # type: ignore
275    def _(self) -> str:
276        return f"You're ratelimited for {self.retry_after}, Endpoint: {self.url}. Slow down!"
277
278    def __str__(self) -> str:
279        return self.message

Raised when too many request status code is returned.

RateLimitedError(url: Union[str, yarl.URL], body: Any, retry_after: float = 0.0)
2def __init__(self, url, body, retry_after=attr_dict['retry_after'].default):
3    self.http_status = attr_dict['http_status'].default
4    self.url = url
5    self.body = body
6    self.retry_after = retry_after
7    self.message = __attr_factory_message(self)
8    BaseException.__init__(self, self.url,self.body,self.retry_after)

Method generated by attrs for class RateLimitedError.

http_status: http.HTTPStatus

The request response http status.

url: Union[str, yarl.URL]

The URL/endpoint caused this error.

body: Any

The response body.

retry_after: float

The amount of seconds you need to wait before retrying to requests.

message: str

A Bungie human readable message describes the cause of the error.

Inherited Members
builtins.BaseException
with_traceback
@typing.final
class RecordState(aiobungie.Flag):
48@typing.final
49class RecordState(enums.Flag):
50    """An enum for records component states."""
51
52    NONE = 0
53    REDEEMED = 1 << 0
54    UNAVAILABLE = 1 << 1
55    OBJECTIVE_NOT_COMPLETED = 1 << 2
56    OBSCURED = 1 << 3
57    INVISIBLE = 1 << 4
58    ENTITLEMENT_UNOWNED = 1 << 5
59    CAN_EQUIP_TITLE = 1 << 6

An enum for records component states.

NONE = <RecordState.NONE: 0>
REDEEMED = <RecordState.REDEEMED: 1>
UNAVAILABLE = <RecordState.UNAVAILABLE: 2>
OBJECTIVE_NOT_COMPLETED = <RecordState.OBJECTIVE_NOT_COMPLETED: 4>
OBSCURED = <RecordState.OBSCURED: 8>
INVISIBLE = <RecordState.INVISIBLE: 16>
ENTITLEMENT_UNOWNED = <RecordState.ENTITLEMENT_UNOWNED: 32>
CAN_EQUIP_TITLE = <RecordState.CAN_EQUIP_TITLE: 64>
Inherited Members
Flag
name
value
@typing.final
class Relationship(builtins.int, aiobungie.Enum):
688@typing.final
689class Relationship(int, Enum):
690    """An enum for bungie friends relationship types."""
691
692    UNKNOWN = 0
693    FRIEND = 1
694    INCOMING_REQUEST = 2
695    OUTGOING_REQUEST = 3

An enum for bungie friends relationship types.

UNKNOWN = <Relationship.UNKNOWN: 0>
FRIEND = <Relationship.FRIEND: 1>
INCOMING_REQUEST = <Relationship.INCOMING_REQUEST: 2>
OUTGOING_REQUEST = <Relationship.OUTGOING_REQUEST: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class RequestMethod(builtins.str, aiobungie.Enum):
181class RequestMethod(str, enums.Enum):
182    """HTTP request methods enum."""
183
184    GET = "GET"
185    """GET methods."""
186    POST = "POST"
187    """POST methods."""
188    PUT = "PUT"
189    """PUT methods."""
190    PATCH = "PATCH"
191    """PATCH methods."""
192    DELETE = "DELETE"
193    """DELETE methods"""

HTTP request methods enum.

GET = <RequestMethod.GET: GET>

GET methods.

POST = <RequestMethod.POST: POST>

POST methods.

PUT = <RequestMethod.PUT: PUT>

PUT methods.

PATCH = <RequestMethod.PATCH: PATCH>

PATCH methods.

DELETE = <RequestMethod.DELETE: DELETE>

DELETE methods

Inherited Members
Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
@attrs.define(auto_exc=True)
class ResponseError(aiobungie.HTTPException):
248@attrs.define(auto_exc=True)
249class ResponseError(HTTPException):
250    """Exception for other HTTP response errors."""

Exception for other HTTP response errors.

ResponseError( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class ResponseError.

Inherited Members
HTTPException
error_code
http_status
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
@typing.final
class Stat(builtins.int, aiobungie.Enum):
515@typing.final
516class Stat(int, Enum):
517    """An Enum for Destiny 2 character stats."""
518
519    NONE = 0
520    MOBILITY = 2996146975
521    RESILIENCE = 392767087
522    RECOVERY = 1943323491
523    DISCIPLINE = 1735777505
524    INTELLECT = 144602215
525    STRENGTH = 4244567218
526    LIGHT_POWER = 1935470627

An Enum for Destiny 2 character stats.

NONE = <Stat.NONE: 0>
MOBILITY = <Stat.MOBILITY: 2996146975>
RESILIENCE = <Stat.RESILIENCE: 392767087>
RECOVERY = <Stat.RECOVERY: 1943323491>
DISCIPLINE = <Stat.DISCIPLINE: 1735777505>
INTELLECT = <Stat.INTELLECT: 144602215>
STRENGTH = <Stat.STRENGTH: 4244567218>
LIGHT_POWER = <Stat.LIGHT_POWER: 1935470627>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
TRACE = 5
@typing.final
class TierType(builtins.int, aiobungie.Enum):
630@typing.final
631class TierType(int, Enum):
632    """An enum for a Destiny 2 item tier type."""
633
634    UNKNOWN = 0
635    CURRENCY = 1
636    BASIC = 2
637    COMMON = 3
638    RARE = 4
639    SUPERIOR = 5
640    EXOTIC = 6

An enum for a Destiny 2 item tier type.

UNKNOWN = <TierType.UNKNOWN: 0>
CURRENCY = <TierType.CURRENCY: 1>
BASIC = <TierType.BASIC: 2>
COMMON = <TierType.COMMON: 3>
RARE = <TierType.RARE: 4>
SUPERIOR = <TierType.SUPERIOR: 5>
EXOTIC = <TierType.EXOTIC: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class TransferStatus(aiobungie.Flag):
740@typing.final
741class TransferStatus(Flag):
742    """An enum for items transfer statuses."""
743
744    CAN_TRANSFER = 0
745    """The item can be transferred."""
746    IS_EQUIPPED = 1 << 0
747    """You can't transfer since the item is equipped."""
748    NOT_TRASNFERRABLE = 1 << 1
749    """This item can not be transferred."""
750    COULD_BE_TRANSFERRED = 1 << 2
751    """You can trasnfer the item. But the place you're trying to put it at has no space for it."""

An enum for items transfer statuses.

CAN_TRANSFER = <TransferStatus.CAN_TRANSFER: 0>

The item can be transferred.

IS_EQUIPPED = <TransferStatus.IS_EQUIPPED: 1>

You can't transfer since the item is equipped.

NOT_TRASNFERRABLE = <TransferStatus.NOT_TRASNFERRABLE: 2>

This item can not be transferred.

COULD_BE_TRANSFERRED = <TransferStatus.COULD_BE_TRANSFERRED: 4>

You can trasnfer the item. But the place you're trying to put it at has no space for it.

Inherited Members
Flag
name
value
UNDEFINED = UNDEFINED
@attrs.define(auto_exc=True)
class Unauthorized(aiobungie.HTTPException):
155@attrs.define(auto_exc=True)
156class Unauthorized(HTTPException):
157    """An exception that's raised when trying to make unauthorized call to a resource and it returns 404."""
158
159    http_status: http.HTTPStatus = attrs.field(
160        default=http.HTTPStatus.UNAUTHORIZED, init=False
161    )

An exception that's raised when trying to make unauthorized call to a resource and it returns 404.

Unauthorized( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class Unauthorized.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
UndefinedOr = typing.Union[aiobungie.UndefinedType, +_T]
class UndefinedType:
33class UndefinedType:
34    """An `UNDEFINED` type."""
35
36    __instance: typing.Optional[UndefinedType] = None
37
38    def __bool__(self) -> typing.Literal[False]:
39        return False
40
41    def __int__(self) -> typing.Literal[0]:
42        return 0
43
44    def __repr__(self) -> str:
45        return "UNDEFINED"
46
47    def __str__(self) -> str:
48        return "UNDEFINED"
49
50    def __new__(cls) -> UndefinedType:
51        if cls.__instance is None:
52            o = super().__new__(cls)
53            cls.__instance = o
54        return cls.__instance

An UNDEFINED type.

UndefinedType()
@typing.final
class ValueUIStyle(builtins.int, aiobungie.Enum):
75@typing.final
76class ValueUIStyle(int, enums.Enum):
77    AUTOMATIC = 0
78    FRACTION = 1
79    CHECK_BOX = 2
80    PERCENTAGE = 3
81    DATETIME = 4
82    FRACTION_FLOAT = 5
83    INTEGER = 6
84    TIME_DURATION = 7
85    HIDDEN = 8
86    MULTIPLIER = 9
87    GREEN_PIPS = 10
88    RED_PIPS = 11
89    EXPLICIT_PERCENTAGE = 12
90    RAW_FLOAT = 13
91    LEVEL_AND_REWARD = 14

An enumeration.

AUTOMATIC = <ValueUIStyle.AUTOMATIC: 0>
FRACTION = <ValueUIStyle.FRACTION: 1>
CHECK_BOX = <ValueUIStyle.CHECK_BOX: 2>
PERCENTAGE = <ValueUIStyle.PERCENTAGE: 3>
DATETIME = <ValueUIStyle.DATETIME: 4>
FRACTION_FLOAT = <ValueUIStyle.FRACTION_FLOAT: 5>
INTEGER = <ValueUIStyle.INTEGER: 6>
TIME_DURATION = <ValueUIStyle.TIME_DURATION: 7>
HIDDEN = <ValueUIStyle.HIDDEN: 8>
MULTIPLIER = <ValueUIStyle.MULTIPLIER: 9>
GREEN_PIPS = <ValueUIStyle.GREEN_PIPS: 10>
RED_PIPS = <ValueUIStyle.RED_PIPS: 11>
EXPLICIT_PERCENTAGE = <ValueUIStyle.EXPLICIT_PERCENTAGE: 12>
RAW_FLOAT = <ValueUIStyle.RAW_FLOAT: 13>
LEVEL_AND_REWARD = <ValueUIStyle.LEVEL_AND_REWARD: 14>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Vendor(builtins.int, aiobungie.Enum):
240@typing.final
241class Vendor(int, Enum):
242    """An Enum for all available vendors in Destiny 2."""
243
244    ZAVALA = 69482069
245    XUR = 2190858386
246    BANSHE = 672118013
247    SPIDER = 863940356
248    SHAXX = 3603221665
249    KADI = 529635856
250    """Postmaster exo."""
251    YUNA = 1796504621
252    """Asia servers only."""
253    EVERVERSE = 3361454721
254    AMANDA = 460529231
255    """Amanda holiday"""
256    CROW = 3611983588
257    HAWTHORNE = 3347378076
258    ADA1 = 350061650
259    DRIFTER = 248695599
260    IKORA = 1976548992
261    SAINT = 765357505
262    """Saint-14"""
263    ERIS_MORN = 1616085565
264    SHAW_HAWN = 1816541247
265    """COSMODROME Guy"""
266    VARIKS = 2531198101

An Enum for all available vendors in Destiny 2.

ZAVALA = <Vendor.ZAVALA: 69482069>
XUR = <Vendor.XUR: 2190858386>
BANSHE = <Vendor.BANSHE: 672118013>
SPIDER = <Vendor.SPIDER: 863940356>
SHAXX = <Vendor.SHAXX: 3603221665>
KADI = <Vendor.KADI: 529635856>

Postmaster exo.

YUNA = <Vendor.YUNA: 1796504621>

Asia servers only.

EVERVERSE = <Vendor.EVERVERSE: 3361454721>
AMANDA = <Vendor.AMANDA: 460529231>

Amanda holiday

CROW = <Vendor.CROW: 3611983588>
HAWTHORNE = <Vendor.HAWTHORNE: 3347378076>
ADA1 = <Vendor.ADA1: 350061650>
DRIFTER = <Vendor.DRIFTER: 248695599>
IKORA = <Vendor.IKORA: 1976548992>
SAINT = <Vendor.SAINT: 765357505>

Saint-14

ERIS_MORN = <Vendor.ERIS_MORN: 1616085565>
SHAW_HAWN = <Vendor.SHAW_HAWN: 1816541247>

COSMODROME Guy

VARIKS = <Vendor.VARIKS: 2531198101>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class WeaponType(builtins.int, aiobungie.Enum):
529@typing.final
530class WeaponType(int, Enum):
531    """Enums for The three Destiny Weapon Types"""
532
533    NONE = 0
534    KINETIC = 1498876634
535    ENERGY = 2465295065
536    POWER = 953998645

Enums for The three Destiny Weapon Types

NONE = <WeaponType.NONE: 0>
KINETIC = <WeaponType.KINETIC: 1498876634>
ENERGY = <WeaponType.ENERGY: 2465295065>
POWER = <WeaponType.POWER: 953998645>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
annotations = _Feature((3, 7, 0, 'beta', 1), (3, 11, 0, 'alpha', 0), 16777216)
def into_iter( iterable: collections.abc.Iterable[~Item]) -> aiobungie.Iterator[~Item]:
559def into_iter(
560    iterable: collections.Iterable[Item],
561) -> Iterator[Item]:
562    """Transform an iterable into an flat iterator.
563
564    Example
565    -------
566    ```py
567    sequence = [1,2,3]
568    for item in aiobungie.into_iter(sequence).reversed():
569        print(item)
570    # 3
571    # 2
572    # 1
573    ```
574
575    Parameters
576    ----------
577    iterable: `typing.Iterable[Item]`
578        The iterable to convert.
579
580    Raises
581    ------
582    `StopIteration`
583        If no elements are left in the iterator.
584    """
585    return Iterator(iterable)

Transform an iterable into an flat iterator.

Example
sequence = [1,2,3]
for item in aiobungie.into_iter(sequence).reversed():
    print(item)
# 3
# 2
# 1
Parameters
  • iterable (typing.Iterable[Item]): The iterable to convert.
Raises
  • StopIteration: If no elements are left in the iterator.
async def raise_error( response: aiohttp.client_reqrep.ClientResponse) -> aiobungie.AiobungieError:
282async def raise_error(response: aiohttp.ClientResponse) -> AiobungieError:
283    """Generates and raise exceptions on error responses."""
284
285    # Not a JSON response, raise immediately.
286
287    # Also Bungie sometimes get funky and return HTML instead of JSON when making an authorized
288    # request with a dummy access token. I can't really do anything about this..
289    if response.content_type != "application/json":
290        return HTTPError(
291            f"Expected JSON content but got {response.content_type!s}, {response.real_url!s}",
292            http.HTTPStatus.UNSUPPORTED_MEDIA_TYPE,
293        )
294
295    body = await response.json()
296    message: str = body.get("Message", "UNDEFINED_MESSAGE")
297    error_status: str = body.get("ErrorStatus", "UNDEFINED_ERROR_STATUS")
298    message_data: dict[str, str] = body.get("MessageData", {})
299    throttle_seconds: int = body.get("ThrottleSeconds", 0)
300    error_code: int = body.get("ErrorCode", 0)
301
302    # Standard HTTP status.
303    if response.status == http.HTTPStatus.NOT_FOUND:
304        return NotFound(
305            message=message,
306            error_code=error_code,
307            throttle_seconds=throttle_seconds,
308            url=str(response.real_url),
309            body=body,
310            headers=response.headers,
311            error_status=error_status,
312            message_data=message_data,
313        )
314
315    elif response.status == http.HTTPStatus.FORBIDDEN:
316        return Forbidden(
317            message=message,
318            error_code=error_code,
319            throttle_seconds=throttle_seconds,
320            url=str(response.real_url),
321            body=body,
322            headers=response.headers,
323            error_status=error_status,
324            message_data=message_data,
325        )
326
327    elif response.status == http.HTTPStatus.UNAUTHORIZED:
328        return Unauthorized(
329            message=message,
330            error_code=error_code,
331            throttle_seconds=throttle_seconds,
332            url=str(response.real_url),
333            body=body,
334            headers=response.headers,
335            error_status=error_status,
336            message_data=message_data,
337        )
338
339    elif response.status == http.HTTPStatus.BAD_REQUEST:
340        # Membership needs to be alone.
341        if error_status == "InvalidParameters":
342            return MembershipTypeError(
343                message=message,
344                body=body,
345                headers=response.headers,
346                url=str(response.url),
347                membership_type=message_data["membershipType"],
348                required_membership=message_data["membershipInfo.membershipType"],
349                membership_id=int(message_data["membershipId"]),
350            )
351        return BadRequest(
352            message=message,
353            body=body,
354            headers=response.headers,
355            url=str(response.url),
356        )
357
358    status = http.HTTPStatus(response.status)
359
360    if 400 <= status < 500:
361        return ResponseError(
362            message=message,
363            error_code=error_code,
364            throttle_seconds=throttle_seconds,
365            url=str(response.real_url),
366            body=body,
367            headers=response.headers,
368            error_status=error_status,
369            message_data=message_data,
370            http_status=status,
371        )
372
373    # Need to self handle ~5xx errors
374    elif 500 <= status < 600:
375        # No API key or method requires OAuth2 most likely.
376        if error_status in {
377            "ApiKeyMissingFromRequest",
378            "WebAuthRequired",
379            "ApiInvalidOrExpiredKey",
380            "AuthenticationInvalid",
381            "AuthorizationCodeInvalid",
382        }:
383            return Unauthorized(
384                message=message,
385                error_code=error_code,
386                throttle_seconds=throttle_seconds,
387                url=str(response.real_url),
388                body=body,
389                headers=response.headers,
390                error_status=error_status,
391                message_data=message_data,
392            )
393
394        # Anything contains not found.
395        elif (
396            "NotFound" in error_status or error_status == "UserCannotFindRequestedUser"
397        ):
398            return NotFound(
399                message=message,
400                error_code=error_code,
401                throttle_seconds=throttle_seconds,
402                url=str(response.real_url),
403                body=body,
404                headers=response.headers,
405                error_status=error_status,
406                message_data=message_data,
407            )
408
409        # Other 5xx errors.
410        else:
411            return InternalServerError(
412                message=message,
413                error_code=error_code,
414                throttle_seconds=throttle_seconds,
415                url=str(response.real_url),
416                body=body,
417                headers=response.headers,
418                error_status=error_status,
419                message_data=message_data,
420                http_status=status,
421            )
422    # Something else.
423    else:
424        return HTTPException(
425            message=message,
426            error_code=error_code,
427            throttle_seconds=throttle_seconds,
428            url=str(response.real_url),
429            body=body,
430            headers=response.headers,
431            error_status=error_status,
432            message_data=message_data,
433            http_status=status,
434        )

Generates and raise exceptions on error responses.

def stringify_http_message(headers: 'collections.Mapping[str, str]') -> str:
437def stringify_http_message(headers: collections.Mapping[str, str]) -> str:
438    return (
439        "{ \n"
440        + "\n".join(  # noqa: W503
441            f"{f'   {key}'}: {value}"
442            if key not in ("Authorization", "X-API-KEY")
443            else f"   {key}: HIDDEN_TOKEN"
444            for key, value in headers.items()
445        )
446        + "\n}"  # noqa: W503
447    )